Fixed bug #17662: Remove deprecated class gzip_encode
[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 * $Id$
31 *
32 * @author Michael Stucki <michael@typo3.org>
33 */
34
35
36 /**
37 * TYPO3 locking class
38 * This class provides an abstract layer to various locking features for TYPO3
39 *
40 * It is intended to blocks requests until some data has been generated.
41 * 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.
42 *
43 * @author Michael Stucki <michael@typo3.org>
44 * @package TYPO3
45 * @subpackage t3lib
46 * @see class.t3lib_tstemplate.php, class.tslib_fe.php
47 */
48 class t3lib_lock {
49 protected $method;
50 protected $id; // Identifier used for this lock
51 protected $resource; // Resource used for this lock (can be a file or a semaphore resource)
52 protected $filepointer;
53 protected $isAcquired = FALSE;
54
55 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.
56 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.
57 protected $syslogFacility = 'cms';
58 protected $isLoggingEnabled = TRUE;
59
60
61 /**
62 * Constructor:
63 * initializes locking, check input parameters and set variables accordingly.
64 *
65 * @param string ID to identify this lock in the system
66 * @param string Define which locking method to use. Defaults to "simple".
67 * @param integer Number of times a locked resource is tried to be acquired. This is only used by manual locks like the "simple" method.
68 * @param integer 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.
69 * @return boolean Returns true unless something went wrong
70 */
71 public function __construct($id, $method = '', $loops = 0, $step = 0) {
72
73 // Input checks
74 $id = (string) $id; // Force ID to be string
75 if (intval($loops)) {
76 $this->loops = intval($loops);
77 }
78 if (intval($step)) {
79 $this->step = intval($step);
80 }
81
82 // Detect locking method
83 if (in_array($method, array('disable', 'simple', 'flock', 'semaphore'))) {
84 $this->method = $method;
85 } else {
86 throw new Exception('No such method "' . $method . '"');
87 }
88
89 $success = FALSE;
90 switch ($this->method) {
91 case 'simple':
92 case 'flock':
93 $path = PATH_site . 'typo3temp/locks/';
94 if (!is_dir($path)) {
95 t3lib_div::mkdir($path);
96 }
97 $this->id = md5($id);
98 $this->resource = $path . $this->id;
99 $success = TRUE;
100 break;
101 case 'semaphore':
102 $this->id = abs(crc32($id));
103 if (($this->resource = sem_get($this->id, 1)) == TRUE) {
104 $success = TRUE;
105 }
106 break;
107 case 'disable':
108 return FALSE;
109 break;
110 }
111
112 return $success;
113 }
114
115 /**
116 * Destructor:
117 * Releases lock automatically when instance is destroyed.
118 *
119 * @return void
120 */
121 function __destruct() {
122 $this->release();
123 }
124
125 /**
126 * Acquire a lock and return when successful. If the lock is already open, the client will be
127 *
128 * 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.
129 *
130 * @return boolean Returns true if lock could be acquired without waiting, false otherwise.
131 */
132 public function acquire() {
133 $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.
134 $isAcquired = TRUE;
135
136 switch ($this->method) {
137 case 'simple':
138 if (is_file($this->resource)) {
139 $this->sysLog('Waiting for a different process to release the lock');
140 $maxExecutionTime = ini_get('max_execution_time');
141 $maxAge = time() - ($maxExecutionTime ? $maxExecutionTime : 120);
142 if (@filectime($this->resource) < $maxAge) {
143 @unlink($this->resource);
144 $this->sysLog('Unlink stale lockfile');
145 }
146 }
147
148 $isAcquired = FALSE;
149 for ($i = 0; $i < $this->loops; $i++) {
150 $filepointer = @fopen($this->resource, 'x');
151 if ($filepointer !== FALSE) {
152 fclose($filepointer);
153 $this->sysLog('Lock aquired');
154 $noWait = ($i === 0);
155 $isAcquired = TRUE;
156 break;
157 }
158 usleep($this->step * 1000);
159 }
160
161 if (!$isAcquired) {
162 throw new Exception('Lock file could not be created');
163 }
164
165 t3lib_div::fixPermissions($this->resource);
166 break;
167 case 'flock':
168 if (($this->filepointer = fopen($this->resource, 'w+')) == FALSE) {
169 throw new Exception('Lock file could not be opened');
170 }
171
172 if (flock($this->filepointer, LOCK_EX | LOCK_NB) == TRUE) { // Lock without blocking
173 $noWait = TRUE;
174 } elseif (flock($this->filepointer, LOCK_EX) == TRUE) { // Lock with blocking (waiting for similar locks to become released)
175 $noWait = FALSE;
176 } else {
177 throw new Exception('Could not lock file "' . $this->resource . '"');
178 }
179 break;
180 case 'semaphore':
181 if (sem_acquire($this->resource)) {
182 // 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.
183 $noWait = FALSE;
184 }
185 break;
186 case 'disable':
187 $noWait = FALSE;
188 $isAcquired = FALSE;
189 break;
190 }
191
192 $this->isAcquired = $isAcquired;
193 return $noWait;
194 }
195
196 /**
197 * Release the lock
198 *
199 * @return boolean Returns TRUE on success or FALSE on failure
200 */
201 public function release() {
202 if (!$this->isAcquired) {
203 return TRUE;
204 }
205
206 $success = TRUE;
207 switch ($this->method) {
208 case 'simple':
209 if (unlink($this->resource) == FALSE) {
210 $success = FALSE;
211 }
212 break;
213 case 'flock':
214 if (flock($this->filepointer, LOCK_UN) == FALSE) {
215 $success = FALSE;
216 }
217 fclose($this->filepointer);
218 unlink($this->resource);
219 break;
220 case 'semaphore':
221 if (@sem_release($this->resource)) {
222 sem_remove($this->resource);
223 } else {
224 $success = FALSE;
225 }
226 break;
227 case 'disable':
228 $success = FALSE;
229 break;
230 }
231
232 $this->isAcquired = FALSE;
233 return $success;
234 }
235
236 /**
237 * Return the locking method which is currently used
238 *
239 * @return string Locking method
240 */
241 public function getMethod() {
242 return $this->method;
243 }
244
245 /**
246 * Return the ID which is currently used
247 *
248 * @return string Locking ID
249 */
250 public function getId() {
251 return $this->id;
252 }
253
254 /**
255 * Return the resource which is currently used.
256 * Depending on the locking method this can be a filename or a semaphore resource.
257 *
258 * @return mixed Locking resource (filename as string or semaphore as resource)
259 */
260 public function getResource() {
261 return $this->resource;
262 }
263
264 /**
265 * Return the status of a lock
266 *
267 * @return string Returns TRUE if lock is acquired, FALSE otherwise
268 */
269 public function getLockStatus() {
270 return $this->isAcquired;
271 }
272
273 /**
274 * Sets the facility (extension name) for the syslog entry.
275 *
276 * @param string $syslogFacility
277 */
278 public function setSyslogFacility($syslogFacility) {
279 $this->syslogFacility = $syslogFacility;
280 }
281
282 /**
283 * Enable/ disable logging
284 *
285 * @param boolean $isLoggingEnabled
286 */
287 public function setEnableLogging($isLoggingEnabled) {
288 $this->isLoggingEnabled = $isLoggingEnabled;
289 }
290
291 /**
292 * Adds a common log entry for this locking API using t3lib_div::sysLog().
293 * Example: 25-02-08 17:58 - cms: Locking [simple::0aeafd2a67a6bb8b9543fb9ea25ecbe2]: Acquired
294 *
295 * @param string $message: The message to be logged
296 * @param integer $severity: Severity - 0 is info (default), 1 is notice, 2 is warning, 3 is error, 4 is fatal error
297 * @return void
298 */
299 public function sysLog($message, $severity = 0) {
300 if ($this->isLoggingEnabled) {
301 t3lib_div::sysLog('Locking [' . $this->method . '::' . $this->id . ']: ' . trim($message), $this->syslogFacility, $severity);
302 }
303 }
304 }
305
306
307 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_lock.php'])) {
308 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/class.t3lib_lock.php']);
309 }
310 ?>