Index: t3lib/formprotection/class.t3lib_formprotection_abstract.php =================================================================== --- t3lib/formprotection/class.t3lib_formprotection_abstract.php (revision 10275) +++ t3lib/formprotection/class.t3lib_formprotection_abstract.php (working copy) @@ -60,7 +60,7 @@ * checking. */ public function __construct() { - $this->retrieveTokens(); + $this->tokens = $this->retrieveTokens(); } /** Index: t3lib/formprotection/class.t3lib_formprotection_backendformprotection.php =================================================================== --- t3lib/formprotection/class.t3lib_formprotection_backendformprotection.php (revision 10275) +++ t3lib/formprotection/class.t3lib_formprotection_backendformprotection.php (working copy) @@ -169,7 +169,22 @@ $tokens = array(); } - $this->tokens = $tokens; + return $tokens; + } + + /** + * It might be that two (or more) scripts are executed at the same time, + * which would lead to a race condition, where both (all) scripts retrieve + * the same tokens from the session, so the script that is executed + * last will overwrite the tokens generated in the first scripts. + * So before writing all tokens back to the session we need to get the + * current tokens from the session again. + * + */ + protected function updateTokens() { + $this->backendUser->user = $this->backendUser->fetchUserSession(TRUE); + $tokens = $this->retrieveTokens(); + $this->tokens = array_merge($this->tokens, $tokens); } /** @@ -179,7 +194,47 @@ * @return void */ public function persistTokens() { + $lockObject = $this->acquireLock(); + + $this->updateTokens(); $this->backendUser->setAndSaveSessionData('formTokens', $this->tokens); + + $this->releaseLock($lockObject); + } + + /** + * Tries to acquire a lock to not allow a race condition. + * + * @return t3lib_lock|FALSE The lock object or FALSE + */ + protected function acquireLock() { + $identifier = 'persistTokens' . $this->backendUser->id; + try { + $lockObject = t3lib_div::makeInstance('t3lib_lock', $identifier, 'simple'); + $lockObject->setEnableLogging(FALSE); + $success = $lockObject->acquire(); + } catch (Exception $e) { + t3lib_div::sysLog('Locking: Failed to acquire lock: '.$e->getMessage(), 't3lib_formprotection_BackendFormProtection', t3lib_div::SYSLOG_SEVERITY_ERROR); + $success = false; // If locking fails, return with false and continue without locking + } + + return $success ? $lockObject : FALSE; + } + + /** + * Releases the lock if it was acquired before. + * + * @return boolean + */ + protected function releaseLock(&$lockObject) { + $success = false; + // If lock object is set and was acquired, release it: + if (is_object($lockObject) && $lockObject instanceof t3lib_lock && $lockObject->getLockStatus()) { + $success = $lockObject->release(); + $lockObject = null; + } + + return $success; } } Index: t3lib/class.t3lib_lock.php =================================================================== --- t3lib/class.t3lib_lock.php (revision 10275) +++ t3lib/class.t3lib_lock.php (working copy) @@ -54,7 +54,8 @@ protected $loops = 150; // Number of times a locked resource is tried to be acquired. This is only used by manual locks like the "simple" method. protected $step = 200; // Milliseconds after lock acquire is retried. $loops * $step results in the maximum delay of a lock. Only used by manual locks like the "simple" method. - + protected $syslogFacility = 'cms'; + protected $isLoggingEnabled = TRUE; /** * Constructor: @@ -269,6 +270,24 @@ } /** + * Sets the facility (extension name) for the syslog entry. + * + * @param string $syslogFacility + */ + public function setSyslogFacility($syslogFacility) { + $this->syslogFacility = $syslogFacility; + } + + /** + * Enable/ disable logging + * + * @param boolean $isLoggingEnabled + */ + public function setEnableLogging($isLoggingEnabled) { + $this->isLoggingEnabled = $isLoggingEnabled; + } + + /** * Adds a common log entry for this locking API using t3lib_div::sysLog(). * Example: 25-02-08 17:58 - cms: Locking [simple::0aeafd2a67a6bb8b9543fb9ea25ecbe2]: Acquired * @@ -277,7 +296,9 @@ * @return void */ public function sysLog($message, $severity = 0) { - t3lib_div::sysLog('Locking [' . $this->method . '::' . $this->id . ']: ' . trim($message), 'cms', $severity); + if ($this->isLoggingEnabled) { + t3lib_div::sysLog('Locking [' . $this->method . '::' . $this->id . ']: ' . trim($message), $this->syslogFacility, $severity); + } } }