[FOLLOWUP][BUGFIX] Reestablish DB connection in long-running tasks 03/43103/2
authorMarkus Klein <markus.klein@typo3.org>
Thu, 27 Aug 2015 17:07:04 +0000 (19:07 +0200)
committerMarkus Klein <markus.klein@typo3.org>
Mon, 7 Sep 2015 19:13:30 +0000 (21:13 +0200)
Reconnecting in isConnected() is not necessary as the next query() will
check the status and reconnect properly if required. Using ping() does
not work with mysqlnd - only if mysqli.reconnect=1 is set. Setting this
is bad practice since a ping() would only reconnect but not properly
reinitialize the charset etc.

Thus a check in Install Tool is added to make sure mysqli.reconnect is
set to "0".

Resolves: #69001
Resolves: #69289
Releases: master, 6.2
Change-Id: I3c2cac91e96fdee8bff113f848341856ec51829b
Reviewed-on: http://review.typo3.org/43103
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Tested-by: Markus Klein <markus.klein@typo3.org>
typo3/sysext/core/Classes/Core/SystemEnvironmentBuilder.php
typo3/sysext/core/Classes/Database/DatabaseConnection.php
typo3/sysext/install/Classes/SystemEnvironment/Check.php
typo3/sysext/scheduler/Classes/Controller/SchedulerModuleController.php

index 5cd4f05..3135cdb 100644 (file)
@@ -478,4 +478,5 @@ class SystemEnvironmentBuilder {
                header('Content-type: text/plain');
                die($message);
        }
+
 }
index d0808b4..d228c9d 100644 (file)
@@ -1612,10 +1612,8 @@ class DatabaseConnection {
                // We think we're still connected
                if ($this->isConnected) {
                        // Check if this is really the case or if the database server has gone away for some reason
+                       // Using mysqlnd ping() does not reconnect (which we would not want anyway since charset etc would not be reinitialized that way)
                        $this->isConnected = $this->link->ping();
-                       if (!$this->isConnected) {
-                               $this->connectDB();
-                       }
                }
                return $this->isConnected;
        }
index 59ed204..5662104 100644 (file)
@@ -86,6 +86,7 @@ class Check {
                $statusArray[] = $this->checkDisableFunctions();
                $statusArray[] = $this->checkDownloadsPossible();
                $statusArray[] = $this->checkSafeMode();
+               $statusArray[] = $this->checkMysqliReconnectSetting();
                $statusArray[] = $this->checkDocRoot();
                $statusArray[] = $this->checkOpenBaseDir();
                $statusArray[] = $this->checkXdebugMaxNestingLevel();
@@ -423,6 +424,30 @@ class Check {
        }
 
        /**
+        * Verify that mysqli.reconnect is set to 0 in order to avoid improper reconnects
+        *
+        * @return Status\StatusInterface
+        */
+       protected function checkMysqliReconnectSetting() {
+
+               $currentMysqliReconnectSetting = ini_get('mysqli.reconnect');
+               if ($currentMysqliReconnectSetting === '1') {
+                       $status = new Status\ErrorStatus();
+                       $status->setTitle('PHP mysqli.reconnect is enabled');
+                       $status->setMessage(
+                               'mysqli.reconnect=1' . LF .
+                               'PHP is configured to automatically reconnect the database connection on disconnection.' . LF .
+                               ' Warning: If (e.g. during a long-running task) the connection is dropped and automatically reconnected, ' .
+                               ' it may not be reinitialized properly (e.g. charset) and write mangled data to the database!'
+                       );
+               } else {
+                       $status = new Status\OkStatus();
+                       $status->setTitle('PHP mysqli.reconnect is fine');
+               }
+               return $status;
+       }
+
+       /**
         * Check if safe mode is enabled
         *
         * @return Status\StatusInterface
index 293d5b0..c7e7ead 100644 (file)
@@ -1125,7 +1125,7 @@ class SchedulerModuleController extends \TYPO3\CMS\Backend\Module\BaseScriptClas
                                                // Check if the last run failed
                                                $failureOutput = '';
                                                if (!empty($schedulerRecord['lastexecution_failure'])) {
-                                                       // Try to get the stored exception object
+                                                       // Try to get the stored exception array
                                                        /** @var $exceptionArray array */
                                                        $exceptionArray = @unserialize($schedulerRecord['lastexecution_failure']);
                                                        if (!is_array($exceptionArray) || empty($exceptionArray)) {