diff --git a/lib/Conf.php b/lib/Conf.php
index 9173d3cb..f15926c3 100644
--- a/lib/Conf.php
+++ b/lib/Conf.php
@@ -35,8 +35,10 @@ class Conf {
public $dbPostgreSQLPort = 5432;
/** @var string Database name on PostgreSQL database server (if using PostgreSQL) */
public $dbPostgreSQLDb = "arsse";
- /** @var string Schema name on PostgreSQL database server (if using PostgreSQL) */
+ /** @var string Schema name in PostgreSQL database (if using PostgreSQL) */
public $dbPostgreSQLSchema = "";
+ /** @var string Service file entry to use (if using PostgreSQL); if using a service entry all above parameters except schema are ignored */
+ public $dbPostgreSQLService = "";
/** @var string Class of the user management driver in use (Internal by default) */
public $userDriver = User\Internal\Driver::class;
diff --git a/lib/Db/PostgreSQL/Driver.php b/lib/Db/PostgreSQL/Driver.php
index 2ba5baa0..7e763e84 100644
--- a/lib/Db/PostgreSQL/Driver.php
+++ b/lib/Db/PostgreSQL/Driver.php
@@ -14,7 +14,7 @@ use JKingWeb\Arsse\Db\ExceptionTimeout;
class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
- public function __construct(string $user = null, string $pass = null, string $db = null, string $host = null, int $port = null, string $schema = null) {
+ public function __construct(string $user = null, string $pass = null, string $db = null, string $host = null, int $port = null, string $schema = null, string $service = null) {
// check to make sure required extension is loaded
if (!static::requirementsMet()) {
throw new Exception("extMissing", self::driverName()); // @codeCoverageIgnore
@@ -25,7 +25,8 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
$host = $host ?? Arsse::$conf->dbPostgreSQLHost;
$port = $port ?? Arsse::$conf->dbPostgreSQLPort;
$schema = $schema ?? Arsse::$conf->dbPostgreSQLSchema;
- $this->makeConnection($user, $pass, $db, $host, $port);
+ $service = $service ?? Arsse::$conf->dbPostgreSQLService;
+ $this->makeConnection($user, $pass, $db, $host, $port, $service);
}
public static function requirementsMet(): bool {
@@ -38,20 +39,38 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
throw new \Exception;
}
- protected function makeConnectionString(bool $pdo, string $user, string $pass, string $db, string $host, int $port): string {
- $out = ['dbname' => $db];
- if ($host != "") {
- $out['host'] = $host;
- $out['port'] = (string) $port;
- }
- if (!$pdo) {
- $out['user'] = $user;
- $out['password'] = $pass;
+ public static function makeConnectionString(bool $pdo, string $user, string $pass, string $db, string $host, int $port, string $service): string {
+ $base = [
+ 'client_encoding' => "UTF8",
+ 'application_name' => "arsse",
+ ];
+ $out = [];
+ if ($service != "") {
+ $out['service'] = $service;
+ } else {
+ if ($host != "") {
+ $out['host'] = $host;
+ }
+ if ($port != 5432 && !($host != "" && $host[0] == "/")) {
+ $out['port'] = (string) $port;
+ }
+ if ($db != "") {
+ $out['dbname'] = $db;
+ }
+ if (!$pdo) {
+ $out['user'] = $user;
+ if ($pass != "") {
+ $out['password'] = $pass;
+ }
+ }
}
+ ksort($out);
+ ksort($base);
+ $out = array_merge($out, $base);
$out = array_map(function($v, $k) {
return "$k='".str_replace("'", "\\'", str_replace("\\", "\\\\", $v))."'";
}, $out, array_keys($out));
- return implode(($pdo ? ";" : " "), $out);
+ return implode(" ", $out);
}
public function __destruct() {
diff --git a/lib/Db/PostgreSQL/PDODriver.php b/lib/Db/PostgreSQL/PDODriver.php
index fd43780e..9bb630ec 100644
--- a/lib/Db/PostgreSQL/PDODriver.php
+++ b/lib/Db/PostgreSQL/PDODriver.php
@@ -20,8 +20,8 @@ class PDODriver extends Driver {
return class_exists("PDO") && in_array("pgsql", \PDO::getAvailableDrivers());
}
- protected function makeConnection(string $user, string $pass, string $db, string $host, int $port) {
- $dsn = $this->makeconnectionString(true, $user, $pass, $db, $host, $port);
+ protected function makeConnection(string $user, string $pass, string $db, string $host, int $port, string $service) {
+ $dsn = $this->makeconnectionString(true, $user, $pass, $db, $host, $port, $service);
$this->db = new \PDO("pgsql:$dsn", $user, $pass);
}
diff --git a/locale/en.php b/locale/en.php
index 55a0bd32..50b8b5fc 100644
--- a/locale/en.php
+++ b/locale/en.php
@@ -20,6 +20,8 @@ return [
'Driver.Db.SQLite3.Name' => 'SQLite 3',
'Driver.Db.SQLite3PDO.Name' => 'SQLite 3 (PDO)',
+ 'Driver.Db.PostgreSQL.Name' => 'PostgreSQL',
+ 'Driver.Db.PostgreSQLPDO.Name' => 'PostgreSQL (PDO)',
'Driver.Service.Curl.Name' => 'HTTP (curl)',
'Driver.Service.Internal.Name' => 'Internal',
'Driver.User.Internal.Name' => 'Internal',
diff --git a/tests/cases/Db/PostgreSQL/TestDriver.php b/tests/cases/Db/PostgreSQL/TestDriver.php
new file mode 100644
index 00000000..59e113bb
--- /dev/null
+++ b/tests/cases/Db/PostgreSQL/TestDriver.php
@@ -0,0 +1,54 @@
+ */
+class TestDriver extends \JKingWeb\Arsse\Test\AbstractTest {
+ /** @dataProvider provideConnectionStrings */
+ public function testGenerateConnectionString(bool $pdo, string $user, string $pass, string $db, string $host, int $port, string $service, string $exp) {
+ $postfix = "application_name='arsse' client_encoding='UTF8'";
+ $act = Driver::makeConnectionString($pdo, $user, $pass, $db, $host, $port, $service);
+ if ($act==$postfix) {
+ $this->assertSame($exp, "");
+ } else {
+ $test = substr($act, 0, strlen($act) - (strlen($postfix) + 1) );
+ $check = substr($act, strlen($test) + 1);
+ $this->assertSame($postfix, $check);
+ $this->assertSame($exp, $test);
+ }
+ }
+
+ public function provideConnectionStrings() {
+ return [
+ [false, "arsse", "secret", "arsse", "", 5432, "", "dbname='arsse' password='secret' user='arsse'"],
+ [false, "arsse", "p word", "arsse", "", 5432, "", "dbname='arsse' password='p word' user='arsse'"],
+ [false, "arsse", "p'word", "arsse", "", 5432, "", "dbname='arsse' password='p\\'word' user='arsse'"],
+ [false, "arsse user", "secret", "arsse db", "", 5432, "", "dbname='arsse db' password='secret' user='arsse user'"],
+ [false, "arsse", "secret", "", "", 5432, "", "password='secret' user='arsse'"],
+ [false, "arsse", "secret", "arsse", "localhost", 5432, "", "dbname='arsse' host='localhost' password='secret' user='arsse'"],
+ [false, "arsse", "secret", "arsse", "", 9999, "", "dbname='arsse' password='secret' port='9999' user='arsse'"],
+ [false, "arsse", "secret", "arsse", "localhost", 9999, "", "dbname='arsse' host='localhost' password='secret' port='9999' user='arsse'"],
+ [false, "arsse", "secret", "arsse", "/socket", 9999, "", "dbname='arsse' host='/socket' password='secret' user='arsse'"],
+ [false, "T'Pau of Vulcan", "", "", "", 5432, "", "user='T\\'Pau of Vulcan'"],
+ [false, "T'Pau of Vulcan", "superman", "datumbase", "somehost", 2112, "arsse", "service='arsse'"],
+ [true, "arsse", "secret", "arsse", "", 5432, "", "dbname='arsse'"],
+ [true, "arsse", "p word", "arsse", "", 5432, "", "dbname='arsse'"],
+ [true, "arsse", "p'word", "arsse", "", 5432, "", "dbname='arsse'"],
+ [true, "arsse user", "secret", "arsse db", "", 5432, "", "dbname='arsse db'"],
+ [true, "arsse", "secret", "", "", 5432, "", ""],
+ [true, "arsse", "secret", "arsse", "localhost", 5432, "", "dbname='arsse' host='localhost'"],
+ [true, "arsse", "secret", "arsse", "", 9999, "", "dbname='arsse' port='9999'"],
+ [true, "arsse", "secret", "arsse", "localhost", 9999, "", "dbname='arsse' host='localhost' port='9999'"],
+ [true, "arsse", "secret", "arsse", "/socket", 9999, "", "dbname='arsse' host='/socket'"],
+ [true, "T'Pau of Vulcan", "", "", "", 5432, "", ""],
+ [true, "T'Pau of Vulcan", "superman", "datumbase", "somehost", 2112, "arsse", "service='arsse'"],
+ ];
+ }
+}
diff --git a/tests/phpunit.xml b/tests/phpunit.xml
index f2a49675..564ced7b 100644
--- a/tests/phpunit.xml
+++ b/tests/phpunit.xml
@@ -55,6 +55,8 @@
cases/Db/SQLite3PDO/TestCreation.php
cases/Db/SQLite3PDO/TestDriver.php
cases/Db/SQLite3PDO/TestUpdate.php
+
+ cases/Db/PostgreSQL/TestDriver.php
cases/Db/SQLite3/Database/TestMiscellany.php