[TASK] Disable compression for inlineJs in Backend
[Packages/TYPO3.CMS.git] / t3lib / class.t3lib_lock.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2008-2011 Michael Stucki (michael@typo3.org)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27 /**
28 * Class for providing locking features in TYPO3
29 *
30 * @author Michael Stucki <michael@typo3.org>
31 */
32
33
34 /**
35 * TYPO3 locking class
36 * This class provides an abstract layer to various locking features for TYPO3
37 *
38 * It is intended to blocks requests until some data has been generated.
39 * This is especially useful if two clients are requesting the same website short after each other. While the request of client 1 triggers building and caching of the website, client 2 will be waiting at this lock.
40 *
41 * @author Michael Stucki <michael@typo3.org>
42 * @package TYPO3
43 * @subpackage t3lib
44 * @see class.t3lib_tstemplate.php, class.tslib_fe.php
45 */
46 class t3lib_lock {
47
48 /**
49 * @var string Locking method: One of 'simple', 'flock', 'semaphore' or 'disable'
50 */
51 protected $method;
52
53 /**
54 * @var mixed Identifier used for this lock
55 */
56 protected $id;
57
58 /**
59 * @var mixed Resource used for this lock (can be a file or a semaphore resource)
60 */
61 protected $resource;
62
63 /**
64 * @var resource File pointer if using flock method
65 */
66 protected $filepointer;
67
68 /**
69 * @var boolean True if lock is acquired
70 */
71 protected $isAcquired = FALSE;
72
73 /**
74 * @var integer Number of times a locked resource is tried to be acquired. Only used in manual locks method "simple".
75 */
76 protected $loops = 150;
77
78 /**
79 * @var integer Milliseconds after lock acquire is retried. $loops * $step results in the maximum delay of a lock. Only used in manual lock method "simple".
80 */
81 protected $step = 200;
82
83 /**
84 * @var string Logging facility
85 */
86 protected $syslogFacility = 'cms';
87
88 /**
89 * @var boolean True if locking should be logged
90 */
91 protected $isLoggingEnabled = TRUE;
92
93
94 /**
95 * Constructor:
96 * initializes locking, check input parameters and set variables accordingly.
97 *
98 * @param string $id ID to identify this lock in the system
99 * @param string $method Define which locking method to use. Defaults to "simple".
100 * @param integer $loops Number of times a locked resource is tried to be acquired. Only used in manual locks method "simple".
101 * @param integer step Milliseconds after lock acquire is retried. $loops * $step results in the maximum delay of a lock. Only used in manual lock method "simple".
102 */
103 public function __construct($id, $method = 'simple', $loops = 0, $step = 0) {
104 // Force ID to be string
105 $id = (string) $id;
106
107 if (intval($loops)) {
108 $this->loops = intval($loops);
109 }
110 if (intval($step)) {
111 $this->step = intval($step);
112 }
113
114 $this->method = $method;
115
116 switch ($this->method) {
117 case 'simple':
118 case 'flock':
119 $path = PATH_site . 'typo3temp/locks/';
120 if (!is_dir($path)) {
121 t3lib_div::mkdir($path);
122 }
123 $this->id = md5($id);
124 $this->resource = $path . $this->id;
125 break;
126 case 'semaphore':
127 $this->id = abs(crc32($id));
128 if (($this->resource = sem_get($this->id, 1)) === FALSE) {
129 throw new Exception(
130 'Unable to get semaphore',
131 1313828196
132 );
133 }
134 break;
135 case 'disable':
136 break;
137 default:
138 throw new InvalidArgumentException(
139 'No such method "' . $method . '"',
140 1294586097
141 );
142 }
143 }
144
145 /**
146 * Destructor:
147 * Releases lock automatically when instance is destroyed.
148 *
149 * @return void
150 */
151 function __destruct() {
152 $this->release();
153 }
154
155 /**
156 * Acquire a lock and return when successful. If the lock is already open, the client will be
157 *
158 * It is important to know that the lock will be acquired in any case, even if the request was blocked first. Therefore, the lock needs to be released in every situation.
159 *
160 * @return boolean Returns TRUE if lock could be acquired without waiting, FALSE otherwise.
161 */
162 public function acquire() {
163 $noWait = TRUE; // Default is TRUE, which means continue without caring for other clients. In the case of TYPO3s cache management, this has no negative effect except some resource overhead.
164 $isAcquired = TRUE;
165
166 switch ($this->method) {
167 case 'simple':
168 if (is_file($this->resource)) {
169 $this->sysLog('Waiting for a different process to release the lock');
170 $maxExecutionTime = ini_get('max_execution_time');
171 $maxAge = time() - ($maxExecutionTime ? $maxExecutionTime : 120);
172 if (@filectime($this->resource) < $maxAge) {
173 @unlink($this->resource);
174 $this->sysLog('Unlink stale lockfile');
175 }
176 }
177
178 $isAcquired = FALSE;
179 for ($i = 0; $i < $this->loops; $i++) {
180 $filepointer = @fopen($this->resource, 'x');
181 if ($filepointer !== FALSE) {
182 fclose($filepointer);
183 $this->sysLog('Lock aquired');
184 $noWait = ($i === 0);
185 $isAcquired = TRUE;
186 break;
187 }
188 usleep($this->step * 1000);
189 }
190
191 if (!$isAcquired) {
192 throw new RuntimeException('Lock file could not be created', 1294586098);
193 }
194
195 t3lib_div::fixPermissions($this->resource);
196 break;
197 case 'flock':
198 if (($this->filepointer = fopen($this->resource, 'w+')) == FALSE) {
199 throw new RuntimeException('Lock file could not be opened', 1294586099);
200 }
201
202 if (flock($this->filepointer, LOCK_EX | LOCK_NB) == TRUE) { // Lock without blocking
203 $noWait = TRUE;
204 } elseif (flock($this->filepointer, LOCK_EX) == TRUE) { // Lock with blocking (waiting for similar locks to become released)
205 $noWait = FALSE;
206 } else {
207 throw new RuntimeException('Could not lock file "' . $this->resource . '"', 1294586100);
208 }
209 break;
210 case 'semaphore':
211 if (sem_acquire($this->resource)) {
212 // Unfortunately it seems not possible to find out if the request was blocked, so we return FALSE in any case to make sure the operation is tried again.
213 $noWait = FALSE;
214 }
215 break;
216 case 'disable':
217 $noWait = FALSE;
218 $isAcquired = FALSE;
219 break;
220 }
221
222 $this->isAcquired = $isAcquired;
223 return $noWait;
224 }
225
226 /**
227 * Release the lock
228 *
229 * @return boolean Returns TRUE on success or FALSE on failure
230 */
231 public function release() {
232 if (!$this->isAcquired) {
233 return TRUE;
234 }
235
236 $success = TRUE;
237 switch ($this->method) {
238 case 'simple':
239 if (t3lib_div::isAllowedAbsPath($this->resource) && t3lib_div::isFirstPartOfStr($this->resource, PATH_site . 'typo3temp/locks/')) {
240 if (unlink($this->resource) == FALSE) {
241 $success = FALSE;
242 }
243 }
244 break;
245 case 'flock':
246 if (flock($this->filepointer, LOCK_UN) == FALSE) {
247 $success = FALSE;
248 }
249 fclose($this->filepointer);
250 if (t3lib_div::isAllowedAbsPath($this->resource) && t3lib_div::isFirstPartOfStr($this->resource, PATH_site . 'typo3temp/locks/')) {
251 unlink($this->resource);
252 }
253 break;
254 case 'semaphore':
255 if (@sem_release($this->resource)) {
256 sem_remove($this->resource);
257 } else {
258 $success = FALSE;
259 }
260 break;
261 case 'disable':
262 $success = FALSE;
263 break;
264 }
265
266 $this->isAcquired = FALSE;
267 return $success;
268 }
269
270 /**
271 * Return the locking method which is currently used
272 *
273 * @return string Locking method
274 */
275 public function getMethod() {
276 return $this->method;
277 }
278
279 /**
280 * Return the ID which is currently used
281 *
282 * @return string Locking ID
283 */
284 public function getId() {
285 return $this->id;
286 }
287
288 /**
289 * Return the resource which is currently used.
290 * Depending on the locking method this can be a filename or a semaphore resource.
291 *
292 * @return mixed Locking resource (filename as string or semaphore as resource)
293 */
294 public function getResource() {
295 return $this->resource;
296 }
297
298 /**
299 * Return the status of a lock
300 *
301 * @return string Returns TRUE if lock is acquired, FALSE otherwise
302 */
303 public function getLockStatus() {
304 return $this->isAcquired;
305 }
306
307 /**
308 * Sets the facility (extension name) for the syslog entry.
309 *
310 * @param string $syslogFacility
311 */
312 public function setSyslogFacility($syslogFacility) {
313 $this->syslogFacility = $syslogFacility;
314 }
315
316 /**
317 * Enable/ disable logging
318 *
319 * @param boolean $isLoggingEnabled
320 */
321 public function setEnableLogging($isLoggingEnabled) {
322 $this->isLoggingEnabled = $isLoggingEnabled;
323 }
324
325 /**
326 * Adds a common log entry for this locking API using t3lib_div::sysLog().
327 * Example: 25-02-08 17:58 - cms: Locking [simple::0aeafd2a67a6bb8b9543fb9ea25ecbe2]: Acquired
328 *
329 * @param string $message: The message to be logged
330 * @param integer $severity: Severity - 0 is info (default), 1 is notice, 2 is warning, 3 is error, 4 is fatal error
331 * @return void
332 */
333 public function sysLog($message, $severity = 0) {
334 if ($this->isLoggingEnabled) {
335 t3lib_div::sysLog('Locking [' . $this->method . '::' . $this->id . ']: ' . trim($message), $this->syslogFacility, $severity);
336 }
337 }
338 }
339
340
341 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_lock.php'])) {
342 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_lock.php']);
343 }
344 ?>