TYPO3 CMS  TYPO3_8-7
SimpleLockStrategy.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Core\Locking;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
20 
25 {
26  const FILE_LOCK_FOLDER = 'typo3temp/var/locks/';
27 
31  protected $filePath;
32 
36  protected $isAcquired = false;
37 
41  protected $loops = 150;
42 
46  protected $step = 200;
47 
52  public function __construct($subject)
53  {
54  // Tests if the directory for simple locks is available.
55  // If not, the directory will be created. The lock path is usually
56  // below typo3temp/var, typo3temp/var itself should exist already
57  $path = PATH_site . self::FILE_LOCK_FOLDER;
58  if (!is_dir($path)) {
59  // Not using mkdir_deep on purpose here, if typo3temp/var itself
60  // does not exist, this issue should be solved on a different
61  // level of the application.
62  if (!GeneralUtility::mkdir($path)) {
63  throw new LockCreateException('Cannot create directory ' . $path, 1460976286);
64  }
65  }
66  if (!is_writable($path)) {
67  throw new LockCreateException('Cannot write to directory ' . $path, 1460976340);
68  }
69  $this->filePath = $path . 'simple_' . md5((string)$subject);
70  }
71 
76  public function init($loops = 0, $step = 0)
77  {
78  $this->loops = (int)$loops;
79  $this->step = (int)$step;
80  }
81 
86  public function __destruct()
87  {
88  $this->release();
89  }
90 
96  public function release()
97  {
98  if (!$this->isAcquired) {
99  return true;
100  }
101 
102  $success = true;
103  if (
104  GeneralUtility::isAllowedAbsPath($this->filePath)
105  && GeneralUtility::isFirstPartOfStr($this->filePath, PATH_site . self::FILE_LOCK_FOLDER)
106  ) {
107  if (@unlink($this->filePath) === false) {
108  $success = false;
109  }
110  }
111 
112  $this->isAcquired = false;
113  return $success;
114  }
115 
121  public function isAcquired()
122  {
123  return $this->isAcquired;
124  }
125 
129  public static function getCapabilities()
130  {
131  return self::LOCK_CAPABILITY_EXCLUSIVE | self::LOCK_CAPABILITY_NOBLOCK;
132  }
133 
141  public function acquire($mode = self::LOCK_CAPABILITY_EXCLUSIVE)
142  {
143  if ($this->isAcquired) {
144  return true;
145  }
146 
147  if (file_exists($this->filePath)) {
148  $maxExecutionTime = (int)ini_get('max_execution_time');
149  $maxAge = time() - ($maxExecutionTime ?: 120);
150  if (@filectime($this->filePath) < $maxAge) {
151  // Remove stale lock file
152  @unlink($this->filePath);
153  }
154  }
155 
156  $this->isAcquired = false;
157  $wouldBlock = false;
158  for ($i = 0; $i < $this->loops; $i++) {
159  $filePointer = @fopen($this->filePath, 'x');
160  if ($filePointer !== false) {
161  fclose($filePointer);
162  GeneralUtility::fixPermissions($this->filePath);
163  $this->isAcquired = true;
164  break;
165  }
166  if ($mode & self::LOCK_CAPABILITY_NOBLOCK) {
167  $wouldBlock = true;
168  break;
169  }
170  usleep($this->step * 1000);
171  }
172 
173  if ($mode & self::LOCK_CAPABILITY_NOBLOCK && !$this->isAcquired && $wouldBlock) {
174  throw new LockAcquireWouldBlockException('Failed to acquire lock because the request would block.', 1460976403);
175  }
176 
177  return $this->isAcquired;
178  }
179 
183  public static function getPriority()
184  {
185  return 50;
186  }
187 
191  public function destroy()
192  {
193  @unlink($this->filePath);
194  }
195 }
static isFirstPartOfStr($str, $partStr)
static fixPermissions($path, $recursive=false)
acquire($mode=self::LOCK_CAPABILITY_EXCLUSIVE)