These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | /* |
||
4 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||
5 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||
6 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||
7 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||
8 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||
9 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||
10 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||
11 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||
12 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
13 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||
14 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
15 | * |
||
16 | * This software consists of voluntary contributions made by many individuals |
||
17 | * and is licensed under the MIT license. For more information, see |
||
18 | * <http://www.doctrine-project.org>. |
||
19 | */ |
||
20 | |||
21 | namespace Doctrine\ORM\Cache\Region; |
||
22 | |||
23 | use Doctrine\ORM\Cache\CollectionCacheEntry; |
||
24 | use Doctrine\ORM\Cache\Lock; |
||
25 | use Doctrine\ORM\Cache\Region; |
||
26 | use Doctrine\ORM\Cache\CacheKey; |
||
27 | use Doctrine\ORM\Cache\CacheEntry; |
||
28 | use Doctrine\ORM\Cache\ConcurrentRegion; |
||
29 | |||
30 | /** |
||
31 | * Very naive concurrent region, based on file locks. |
||
32 | * |
||
33 | * @since 2.5 |
||
34 | * @author Fabio B. Silva <fabio.bat.silvagmail.com> |
||
35 | */ |
||
36 | class FileLockRegion implements ConcurrentRegion |
||
37 | { |
||
38 | const LOCK_EXTENSION = 'lock'; |
||
39 | |||
40 | /** |
||
41 | * var \Doctrine\ORM\Cache\Region |
||
42 | */ |
||
43 | private $region; |
||
44 | |||
45 | /** |
||
46 | * @var string |
||
47 | */ |
||
48 | private $directory; |
||
49 | |||
50 | /** |
||
51 | * var integer |
||
52 | */ |
||
53 | private $lockLifetime; |
||
54 | |||
55 | /** |
||
56 | * @param \Doctrine\ORM\Cache\Region $region |
||
57 | * @param string $directory |
||
58 | * @param string $lockLifetime |
||
59 | * |
||
60 | * @throws \InvalidArgumentException |
||
61 | */ |
||
62 | 12 | public function __construct(Region $region, $directory, $lockLifetime) |
|
63 | { |
||
64 | 12 | if ( ! is_dir($directory) && ! @mkdir($directory, 0775, true)) { |
|
65 | throw new \InvalidArgumentException(sprintf('The directory "%s" does not exist and could not be created.', $directory)); |
||
66 | } |
||
67 | |||
68 | 12 | if ( ! is_writable($directory)) { |
|
69 | throw new \InvalidArgumentException(sprintf('The directory "%s" is not writable.', $directory)); |
||
70 | } |
||
71 | |||
72 | 12 | $this->region = $region; |
|
73 | 12 | $this->directory = $directory; |
|
74 | 12 | $this->lockLifetime = $lockLifetime; |
|
75 | 12 | } |
|
76 | |||
77 | /** |
||
78 | * @param \Doctrine\ORM\Cache\CacheKey $key |
||
79 | * @param \Doctrine\ORM\Cache\Lock $lock |
||
80 | * |
||
81 | * @return boolean |
||
82 | */ |
||
83 | 10 | private function isLocked(CacheKey $key, Lock $lock = null) |
|
84 | { |
||
85 | 10 | $filename = $this->getLockFileName($key); |
|
86 | |||
87 | 10 | if ( ! is_file($filename)) { |
|
88 | 10 | return false; |
|
89 | } |
||
90 | |||
91 | 6 | $time = $this->getLockTime($filename); |
|
92 | 6 | $content = $this->getLockContent($filename); |
|
93 | |||
94 | 6 | if ( ! $content || ! $time) { |
|
95 | @unlink($filename); |
||
0 ignored issues
–
show
|
|||
96 | |||
97 | return false; |
||
98 | } |
||
99 | |||
100 | 6 | if ($lock && $content === $lock->value) { |
|
101 | 1 | return false; |
|
102 | } |
||
103 | |||
104 | // outdated lock |
||
105 | 6 | if (($time + $this->lockLifetime) <= time()) { |
|
106 | 1 | @unlink($filename); |
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
107 | |||
108 | 1 | return false; |
|
109 | } |
||
110 | |||
111 | 5 | return true; |
|
112 | } |
||
113 | |||
114 | /** |
||
115 | * @param \Doctrine\ORM\Cache\CacheKey $key |
||
116 | * |
||
117 | * @return string |
||
118 | */ |
||
119 | 10 | private function getLockFileName(CacheKey $key) |
|
120 | { |
||
121 | 10 | return $this->directory . DIRECTORY_SEPARATOR . $key->hash . '.' . self::LOCK_EXTENSION; |
|
122 | } |
||
123 | |||
124 | /** |
||
125 | * @param string $filename |
||
126 | * |
||
127 | * @return string |
||
128 | */ |
||
129 | 6 | private function getLockContent($filename) |
|
130 | { |
||
131 | 6 | return @file_get_contents($filename); |
|
132 | } |
||
133 | |||
134 | /** |
||
135 | * @param string $filename |
||
136 | * |
||
137 | * @return integer |
||
138 | */ |
||
139 | 6 | private function getLockTime($filename) |
|
140 | { |
||
141 | 6 | return @fileatime($filename); |
|
142 | } |
||
143 | |||
144 | /** |
||
145 | * {@inheritdoc} |
||
146 | */ |
||
147 | 1 | public function getName() |
|
148 | { |
||
149 | 1 | return $this->region->getName(); |
|
150 | } |
||
151 | |||
152 | /** |
||
153 | * {@inheritdoc} |
||
154 | */ |
||
155 | 10 | public function contains(CacheKey $key) |
|
156 | { |
||
157 | 10 | if ($this->isLocked($key)) { |
|
158 | 5 | return false; |
|
159 | } |
||
160 | |||
161 | 10 | return $this->region->contains($key); |
|
162 | } |
||
163 | |||
164 | /** |
||
165 | * {@inheritdoc} |
||
166 | */ |
||
167 | 6 | public function get(CacheKey $key) |
|
168 | { |
||
169 | 6 | if ($this->isLocked($key)) { |
|
170 | 3 | return null; |
|
171 | } |
||
172 | |||
173 | 3 | return $this->region->get($key); |
|
174 | } |
||
175 | |||
176 | /** |
||
177 | * {@inheritdoc} |
||
178 | */ |
||
179 | public function getMultiple(CollectionCacheEntry $collection) |
||
180 | { |
||
181 | if (array_filter(array_map([$this, 'isLocked'], $collection->identifiers))) { |
||
182 | return null; |
||
183 | } |
||
184 | |||
185 | return $this->region->getMultiple($collection); |
||
186 | } |
||
187 | |||
188 | /** |
||
189 | * {@inheritdoc} |
||
190 | */ |
||
191 | 10 | public function put(CacheKey $key, CacheEntry $entry, Lock $lock = null) |
|
192 | { |
||
193 | 10 | if ($this->isLocked($key, $lock)) { |
|
194 | 1 | return false; |
|
195 | } |
||
196 | |||
197 | 10 | return $this->region->put($key, $entry); |
|
198 | } |
||
199 | |||
200 | /** |
||
201 | * {@inheritdoc} |
||
202 | */ |
||
203 | 3 | public function evict(CacheKey $key) |
|
204 | { |
||
205 | 3 | if ($this->isLocked($key)) { |
|
206 | 1 | @unlink($this->getLockFileName($key)); |
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
207 | } |
||
208 | |||
209 | 3 | return $this->region->evict($key); |
|
210 | } |
||
211 | |||
212 | /** |
||
213 | * {@inheritdoc} |
||
214 | */ |
||
215 | 3 | public function evictAll() |
|
216 | { |
||
217 | // The check below is necessary because on some platforms glob returns false |
||
218 | // when nothing matched (even though no errors occurred) |
||
219 | 3 | $filenames = glob(sprintf("%s/*.%s" , $this->directory, self::LOCK_EXTENSION)); |
|
220 | |||
221 | 3 | if ($filenames) { |
|
222 | 1 | foreach ($filenames as $filename) { |
|
223 | 1 | @unlink($filename); |
|
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
224 | } |
||
225 | } |
||
226 | |||
227 | 3 | return $this->region->evictAll(); |
|
228 | } |
||
229 | |||
230 | /** |
||
231 | * {@inheritdoc} |
||
232 | */ |
||
233 | 6 | public function lock(CacheKey $key) |
|
234 | { |
||
235 | 6 | if ($this->isLocked($key)) { |
|
236 | 1 | return null; |
|
237 | } |
||
238 | |||
239 | 5 | $lock = Lock::createLockRead(); |
|
240 | 5 | $filename = $this->getLockFileName($key); |
|
241 | |||
242 | 5 | if ( ! @file_put_contents($filename, $lock->value, LOCK_EX)) { |
|
243 | return null; |
||
244 | } |
||
245 | 5 | chmod($filename, 0664); |
|
246 | |||
247 | 5 | return $lock; |
|
248 | } |
||
249 | |||
250 | /** |
||
251 | * {@inheritdoc} |
||
252 | */ |
||
253 | 2 | public function unlock(CacheKey $key, Lock $lock) |
|
254 | { |
||
255 | 2 | if ($this->isLocked($key, $lock)) { |
|
256 | 1 | return false; |
|
257 | } |
||
258 | |||
259 | 1 | if ( ! @unlink($this->getLockFileName($key))) { |
|
260 | return false; |
||
261 | } |
||
262 | |||
263 | 1 | return true; |
|
264 | } |
||
265 | } |
||
266 |
If you suppress an error, we recommend checking for the error condition explicitly: