[TASK] Add SystemStatusCheck for PostgreSQL 68/51368/6
authorManuel Selbach <manuel_selbach@yahoo.de>
Fri, 20 Jan 2017 08:59:49 +0000 (09:59 +0100)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Mon, 27 Feb 2017 18:11:43 +0000 (19:11 +0100)
The SystemStatusCheck for PostgreSQL checks the server and the libpq version.
It’s important to use the correct libpq version as this will lead to problems
if it differs to much from the server version.

Change-Id: I370b57cc8e516624ee7a299b0c3710d834175386
Resolves: #79331
Releases: master
Reviewed-on: https://review.typo3.org/51368
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Manuel Selbach <manuel_selbach@yahoo.de>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
typo3/sysext/install/Classes/SystemEnvironment/Check.php
typo3/sysext/install/Classes/SystemEnvironment/CheckInterface.php [new file with mode: 0644]
typo3/sysext/install/Classes/SystemEnvironment/DatabaseCheck.php
typo3/sysext/install/Classes/SystemEnvironment/DatabasePlatform/MySqlCheck.php [new file with mode: 0644]
typo3/sysext/install/Classes/SystemEnvironment/DatabasePlatform/PostgreSqlCheck.php [new file with mode: 0644]
typo3/sysext/install/Classes/SystemEnvironment/SetupCheck.php

index 087d7c6..7760796 100644 (file)
@@ -44,7 +44,7 @@ use TYPO3\CMS\Install\Status;
  * text only. The return values of this class are not bound to HTML
  * and can be used in different scopes (eg. as json array).
  */
-class Check
+class Check implements CheckInterface
 {
     /**
      * @var array List of required PHP extensions
@@ -70,7 +70,7 @@ class Check
      *
      * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
      */
-    public function getStatus()
+    public function getStatus(): array
     {
         $status = [];
         $status[] = $this->checkCurrentDirectoryIsInIncludePath();
diff --git a/typo3/sysext/install/Classes/SystemEnvironment/CheckInterface.php b/typo3/sysext/install/Classes/SystemEnvironment/CheckInterface.php
new file mode 100644 (file)
index 0000000..be33574
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+
+namespace TYPO3\CMS\Install\SystemEnvironment;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Check system environment status
+ *
+ * This interface needs to be implemented by hardcoded requirement
+ * checks of the underlying server and PHP system.
+ *
+ * The status messages and title *must not* include HTML, use
+ * plain text only. The return values of this class can be used
+ * in different scopes (eg. as json array).
+ */
+interface CheckInterface
+{
+    /**
+     * Get all status information as array with status objects
+     *
+     * @return \TYPO3\CMS\Install\Status\StatusInterface[]
+     */
+    public function getStatus(): array;
+}
index df6122b..02db02f 100644 (file)
@@ -13,12 +13,9 @@ namespace TYPO3\CMS\Install\SystemEnvironment;
  *
  * The TYPO3 project - inspiring people to share!
  */
-
-use TYPO3\CMS\Core\Database\Connection;
-use TYPO3\CMS\Core\Database\ConnectionPool;
-use TYPO3\CMS\Core\Database\Query\QueryBuilder;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Install\Status;
+use TYPO3\CMS\Install\SystemEnvironment\DatabasePlatform\MySqlCheck;
+use TYPO3\CMS\Install\SystemEnvironment\DatabasePlatform\PostgreSqlCheck;
 
 /**
  * Check database configuration status
@@ -29,135 +26,31 @@ use TYPO3\CMS\Install\Status;
  * text only. The return values of this class are not bound to HTML
  * and can be used in different scopes (eg. as json array).
  */
-class DatabaseCheck
+class DatabaseCheck implements CheckInterface
 {
     /**
-     * List of MySQL modes that are incompatible with TYPO3 CMS
+     * List of database platforms to check
      *
      * @var array
      */
-    protected $incompatibleSqlModes = [
-        'NO_BACKSLASH_ESCAPES'
+    protected $databasePlatformChecks = [
+        MySqlCheck::class,
+        PostgreSqlCheck::class,
     ];
 
     /**
-     * Get all status information as array with status objects
+     * Get status of each database platform defined in the list
      *
-     * @return \TYPO3\CMS\Install\Status\StatusInterface[]
+     * @return array
+     * @throws \InvalidArgumentException
      */
-    public function getStatus()
+    public function getStatus(): array
     {
-        $statusArray = [];
-        $defaultConnection = GeneralUtility::makeInstance(ConnectionPool::class)
-            ->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME);
-        if (strpos($defaultConnection->getServerVersion(), 'MySQL') !== 0) {
-            return $statusArray;
-        }
-        $statusArray[] = $this->checkMysqlVersion($defaultConnection);
-        $statusArray[] = $this->checkInvalidSqlModes($defaultConnection);
-        $statusArray[] = $this->checkMysqlDatabaseUtf8Status($defaultConnection);
-        return $statusArray;
-    }
+        $databaseStatus = [];
 
-    /**
-     * Check if any SQL mode is set which is not compatible with TYPO3
-     *
-     * @param Connection Connection to the database to be checked
-     * @return Status\StatusInterface
-     */
-    protected function checkInvalidSqlModes($connection)
-    {
-        $detectedIncompatibleSqlModes = $this->getIncompatibleSqlModes($connection);
-        if (!empty($detectedIncompatibleSqlModes)) {
-            $status = new Status\ErrorStatus();
-            $status->setTitle('Incompatible SQL modes found!');
-            $status->setMessage(
-                'Incompatible SQL modes have been detected:' .
-                ' ' . implode(', ', $detectedIncompatibleSqlModes) . '.' .
-                ' The listed modes are not compatible with TYPO3 CMS.' .
-                ' You have to change that setting in your MySQL environment' .
-                ' or in $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'setDBinit\']'
-            );
-        } else {
-            $status = new Status\OkStatus();
-            $status->setTitle('No incompatible SQL modes found.');
-        }
-
-        return $status;
-    }
-
-    /**
-     * Check minimum MySQL version
-     *
-     * @param Connection Connection to the database to be checked
-     * @return Status\StatusInterface
-     */
-    protected function checkMysqlVersion($connection)
-    {
-        $minimumMysqlVersion = '5.5.0';
-        preg_match('/MySQL ((\d+\.)*(\d+\.)*\d+)/', $connection->getServerVersion(), $match);
-        $currentMysqlVersion = $match[1];
-        if (version_compare($currentMysqlVersion, $minimumMysqlVersion) < 0) {
-            $status = new Status\ErrorStatus();
-            $status->setTitle('MySQL version too low');
-            $status->setMessage(
-                'Your MySQL version ' . $currentMysqlVersion . ' is too old. TYPO3 CMS does not run' .
-                ' with this version. Update to at least MySQL ' . $minimumMysqlVersion
-            );
-        } else {
-            $status = new Status\OkStatus();
-            $status->setTitle('MySQL version is fine');
+        foreach ($this->databasePlatformChecks as $databasePlatformCheckClass) {
+            $databaseStatus += GeneralUtility::makeInstance($databasePlatformCheckClass)->getStatus();
         }
-
-        return $status;
-    }
-
-    /**
-     * Checks the character set of the database and reports an error if it is not utf-8.
-     *
-     * @param Connection $connection to the database to be checked
-     * @return Status\StatusInterface
-     */
-    protected function checkMysqlDatabaseUtf8Status(Connection $connection)
-    {
-        /** @var QueryBuilder $queryBuilder */
-        $queryBuilder = $connection->createQueryBuilder();
-        $defaultDatabaseCharset = (string)$queryBuilder->select('DEFAULT_CHARACTER_SET_NAME')
-            ->from('information_schema.SCHEMATA')
-            ->where(
-                $queryBuilder->expr()->eq(
-                    'SCHEMA_NAME',
-                    $queryBuilder->createNamedParameter($connection->getDatabase(), \PDO::PARAM_STR)
-                )
-            )
-            ->setMaxResults(1)
-            ->execute()
-            ->fetchColumn();
-        // also allow utf8mb4
-        if (strpos($defaultDatabaseCharset, 'utf8') !== 0) {
-            $status = new Status\ErrorStatus();
-            $status->setTitle('MySQL database character set check failed');
-            $status->setMessage(
-                'Checking database character set failed, got key "'
-                . $defaultDatabaseCharset . '" instead of "utf8" or "utf8mb4"'
-            );
-        } else {
-            $status = new Status\OkStatus();
-            $status->setTitle('Your database uses utf-8. All good.');
-        }
-        return $status;
-    }
-
-    /**
-     * Returns an array with the current sql mode settings
-     *
-     * @param Connection Connection to the database to be checked
-     * @return array Contains all configured SQL modes that are incompatible
-     */
-    protected function getIncompatibleSqlModes($connection)
-    {
-        $sqlModes = explode(',', $connection->executeQuery('SELECT @@SESSION.sql_mode;')
-            ->fetch(0)['@@SESSION.sql_mode']);
-        return array_intersect($this->incompatibleSqlModes, $sqlModes);
+        return $databaseStatus;
     }
 }
diff --git a/typo3/sysext/install/Classes/SystemEnvironment/DatabasePlatform/MySqlCheck.php b/typo3/sysext/install/Classes/SystemEnvironment/DatabasePlatform/MySqlCheck.php
new file mode 100644 (file)
index 0000000..5699584
--- /dev/null
@@ -0,0 +1,173 @@
+<?php
+
+namespace TYPO3\CMS\Install\SystemEnvironment\DatabasePlatform;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Database\Connection;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Database\Query\QueryBuilder;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Install\Status;
+use TYPO3\CMS\Install\SystemEnvironment\CheckInterface;
+
+/**
+ * Check database configuration status for MySQL server
+ *
+ * This class is a hardcoded requirement check for the database server.
+ *
+ * The status messages and title *must not* include HTML, use plain
+ * text only. The return values of this class are not bound to HTML
+ * and can be used in different scopes (eg. as json array).
+ */
+class MySqlCheck implements CheckInterface
+{
+    /**
+     * Minimum supported MySQL version
+     *
+     * @var string
+     */
+    protected $minimumMySQLVersion = '5.5.0';
+
+    /**
+     * List of MySQL modes that are incompatible with TYPO3 CMS
+     *
+     * @var array
+     */
+    protected $incompatibleSqlModes = [
+        'NO_BACKSLASH_ESCAPES'
+    ];
+
+    /**
+     * Get all status information as array with status objects
+     *
+     * @return \TYPO3\CMS\Install\Status\StatusInterface[]
+     * @throws \InvalidArgumentException
+     * @throws \Doctrine\DBAL\DBALException
+     */
+    public function getStatus(): array
+    {
+        $statusArray = [];
+        $defaultConnection = GeneralUtility::makeInstance(ConnectionPool::class)
+            ->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME);
+        if (strpos($defaultConnection->getServerVersion(), 'MySQL') !== 0) {
+            return $statusArray;
+        }
+        $statusArray[] = $this->checkMysqlVersion($defaultConnection);
+        $statusArray[] = $this->checkInvalidSqlModes($defaultConnection);
+        $statusArray[] = $this->checkMysqlDatabaseUtf8Status($defaultConnection);
+        return $statusArray;
+    }
+
+    /**
+     * Check if any SQL mode is set which is not compatible with TYPO3
+     *
+     * @param Connection Connection to the database to be checked
+     * @return Status\StatusInterface
+     */
+    protected function checkInvalidSqlModes($connection)
+    {
+        $detectedIncompatibleSqlModes = $this->getIncompatibleSqlModes($connection);
+        if (!empty($detectedIncompatibleSqlModes)) {
+            $status = new Status\ErrorStatus();
+            $status->setTitle('Incompatible SQL modes found!');
+            $status->setMessage(
+                'Incompatible SQL modes have been detected:' .
+                ' ' . implode(', ', $detectedIncompatibleSqlModes) . '.' .
+                ' The listed modes are not compatible with TYPO3 CMS.' .
+                ' You have to change that setting in your MySQL environment' .
+                ' or in $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'setDBinit\']'
+            );
+        } else {
+            $status = new Status\OkStatus();
+            $status->setTitle('No incompatible SQL modes found.');
+        }
+
+        return $status;
+    }
+
+    /**
+     * Check minimum MySQL version
+     *
+     * @param Connection Connection to the database to be checked
+     * @return Status\StatusInterface
+     */
+    protected function checkMysqlVersion($connection)
+    {
+        preg_match('/MySQL ((\d+\.)*(\d+\.)*\d+)/', $connection->getServerVersion(), $match);
+        $currentMysqlVersion = $match[1];
+        if (version_compare($currentMysqlVersion, $this->minimumMySQLVersion, '<')) {
+            $status = new Status\ErrorStatus();
+            $status->setTitle('MySQL version too low');
+            $status->setMessage(
+                'Your MySQL version ' . $currentMysqlVersion . ' is too old. TYPO3 CMS does not run' .
+                ' with this version. Update to at least MySQL ' . $this->minimumMySQLVersion
+            );
+        } else {
+            $status = new Status\OkStatus();
+            $status->setTitle('MySQL version is fine');
+        }
+
+        return $status;
+    }
+
+    /**
+     * Checks the character set of the database and reports an error if it is not utf-8.
+     *
+     * @param Connection $connection to the database to be checked
+     * @return Status\StatusInterface
+     */
+    protected function checkMysqlDatabaseUtf8Status(Connection $connection)
+    {
+        /** @var QueryBuilder $queryBuilder */
+        $queryBuilder = $connection->createQueryBuilder();
+        $defaultDatabaseCharset = (string)$queryBuilder->select('DEFAULT_CHARACTER_SET_NAME')
+            ->from('information_schema.SCHEMATA')
+            ->where(
+                $queryBuilder->expr()->eq(
+                    'SCHEMA_NAME',
+                    $queryBuilder->createNamedParameter($connection->getDatabase(), \PDO::PARAM_STR)
+                )
+            )
+            ->setMaxResults(1)
+            ->execute()
+            ->fetchColumn();
+        // also allow utf8mb4
+        if (strpos($defaultDatabaseCharset, 'utf8') !== 0) {
+            $status = new Status\ErrorStatus();
+            $status->setTitle('MySQL database character set check failed');
+            $status->setMessage(
+                'Checking database character set failed, got key "'
+                . $defaultDatabaseCharset . '" instead of "utf8" or "utf8mb4"'
+            );
+        } else {
+            $status = new Status\OkStatus();
+            $status->setTitle('Your database uses utf-8. All good.');
+        }
+        return $status;
+    }
+
+    /**
+     * Returns an array with the current sql mode settings
+     *
+     * @param Connection Connection to the database to be checked
+     * @return array Contains all configured SQL modes that are incompatible
+     */
+    protected function getIncompatibleSqlModes($connection)
+    {
+        $sqlModes = explode(',', $connection->executeQuery('SELECT @@SESSION.sql_mode;')
+            ->fetch(0)['@@SESSION.sql_mode']);
+        return array_intersect($this->incompatibleSqlModes, $sqlModes);
+    }
+}
diff --git a/typo3/sysext/install/Classes/SystemEnvironment/DatabasePlatform/PostgreSqlCheck.php b/typo3/sysext/install/Classes/SystemEnvironment/DatabasePlatform/PostgreSqlCheck.php
new file mode 100644 (file)
index 0000000..98f8e0e
--- /dev/null
@@ -0,0 +1,130 @@
+<?php
+
+namespace TYPO3\CMS\Install\SystemEnvironment\DatabasePlatform;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Database\Connection;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Install\Status;
+use TYPO3\CMS\Install\SystemEnvironment\CheckInterface;
+
+/**
+ * Check database configuration status for PostgreSQL
+ *
+ * This class is a hardcoded requirement check for the database server.
+ *
+ * The status messages and title *must not* include HTML, use plain
+ * text only. The return values of this class are not bound to HTML
+ * and can be used in different scopes (eg. as json array).
+ */
+class PostgreSqlCheck implements CheckInterface
+{
+    /**
+     * Minimum supported PostgreSQL Server version
+     *
+     * @var string
+     */
+    protected $minimumPostgreSQLVerion = '9.2';
+
+    /**
+     * Minimum supported libpq version
+     * @var string
+     */
+    protected $minimumLibPQVersion = '9.0';
+
+    /**
+     * Get all status information as array with status objects
+     *
+     * @return array
+     * @throws \Doctrine\DBAL\DBALException
+     * @throws \InvalidArgumentException
+     */
+    public function getStatus(): array
+    {
+        $statusArray = [];
+        $defaultConnection = GeneralUtility::makeInstance(ConnectionPool::class)
+            ->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME);
+        if (strpos($defaultConnection->getServerVersion(), 'PostgreSQL') !== 0) {
+            return $statusArray;
+        }
+
+        $statusArray[] = $this->checkPostgreSqlVersion($defaultConnection);
+        $statusArray[] = $this->checkLibpqVersion();
+        return $statusArray;
+    }
+
+    /**
+     * Check minimum PostgreSQL version
+     *
+     * @param Connection Connection to the database to be checked
+     * @return Status\StatusInterface
+     */
+    protected function checkPostgreSqlVersion($connection): Status\StatusInterface
+    {
+        preg_match('/PostgreSQL ((\d+\.)*(\d+\.)*\d+)/', $connection->getServerVersion(), $match);
+        $currentPostgreSqlVersion = $match[1];
+        if (version_compare($currentPostgreSqlVersion, $this->minimumPostgreSQLVerion, '<')) {
+            $status = new Status\ErrorStatus();
+            $status->setTitle('PostgreSQL Server version is unsupported');
+            $status->setMessage(
+                'Your PostgreSQL version ' . $currentPostgreSqlVersion . ' is not supported. TYPO3 CMS does not run' .
+                ' with this version. The minimum supported PostgreSQL version is ' . $this->minimumPostgreSQLVerion
+            );
+        } else {
+            $status = new Status\OkStatus();
+            $status->setTitle('PostgreSQL Server version is supported');
+        }
+
+        return $status;
+    }
+
+    /**
+     * Check the version of ligpq within the PostgreSQL driver
+     *
+     * @return Status\StatusInterface
+     */
+    protected function checkLibpqVersion(): Status\StatusInterface
+    {
+        if (!defined('PGSQL_LIBPQ_VERSION_STR')) {
+            $status = new Status\WarningStatus();
+            $status->setTitle('PostgreSQL libpq version cannot be determined');
+            $status->setMessage(
+                'It is not possible to retrieve your PostgreSQL libpq version. Please check the version' .
+                ' in the "phpinfo" area of the "System environment" module in the install tool manually.' .
+                ' This should be found in section "pdo_pgsql".' .
+                ' You should have at least the following version of  PostgreSQL libpq installed: ' .
+                $this->minimumLibPQVersion
+            );
+        } else {
+            preg_match('/PostgreSQL ((\d+\.)*(\d+\.)*\d+)/', \PGSQL_LIBPQ_VERSION_STR, $match);
+            $currentPostgreSqlLibpqVersion = $match[1];
+
+            if (version_compare($currentPostgreSqlLibpqVersion, $this->minimumLibPQVersion, '<')) {
+                $status = new Status\ErrorStatus();
+                $status->setTitle('PostgreSQL libpq version is unsupported');
+                $status->setMessage(
+                    'Your PostgreSQL libpq version "' . $currentPostgreSqlLibpqVersion . '" is unsupported.' .
+                    ' TYPO3 CMS does not run with this version. The minimum supported libpq version is ' .
+                    $this->minimumLibPQVersion
+                );
+            } else {
+                $status = new Status\OkStatus();
+                $status->setTitle('PostgreSQL libpq version is supported');
+            }
+        }
+        return $status;
+    }
+}
index 14c19c1..a9fa51a 100644 (file)
@@ -27,14 +27,14 @@ use TYPO3\CMS\Install\Status;
  * text only. The return values of this class are not bound to HTML
  * and can be used in different scopes (eg. as json array).
  */
-class SetupCheck
+class SetupCheck implements CheckInterface
 {
     /**
      * Get all status information as array with status objects
      *
      * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
      */
-    public function getStatus()
+    public function getStatus(): array
     {
         $status = [];