Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
cacheenginefiles.php
1<?php
2namespace Bitrix\Main\Data;
3
5
7{
8 private $ttl;
9
10 //cache stats
11 private $written = false;
12 private $read = false;
13 private $path = '';
14
15 protected $useLock = false;
16 protected static $lockHandles = array();
17
22 public function __construct($options = [])
23 {
24 $config = Main\Config\Configuration::getValue("cache");
25 if ($config && is_array($config) && isset($config["use_lock"]))
26 {
27 $this->useLock = (bool)$config["use_lock"];
28 }
29
30 if (!empty($options) && isset($options['actual_data']))
31 {
32 $this->useLock = !((bool) $options['actual_data']);
33 }
34 }
35
41 public function getReadBytes()
42 {
43 return $this->read;
44 }
45
51 public function getWrittenBytes()
52 {
53 return $this->written;
54 }
55
61 public function getCachePath()
62 {
63 return $this->path;
64 }
65
71 public function isAvailable()
72 {
73 return true;
74 }
75
83 private static function unlink($fileName)
84 {
85 if (isset(self::$lockHandles[$fileName]) && self::$lockHandles[$fileName])
86 {
87 fclose(self::$lockHandles[$fileName]);
88 unset(self::$lockHandles[$fileName]);
89 }
90
91 if (file_exists($fileName))
92 {
93 @chmod($fileName, BX_FILE_PERMISSIONS);
94 @unlink($fileName);
95 }
96 }
97
103 private static function addAgent()
104 {
105 global $APPLICATION;
106
107 static $agentAdded = false;
108 if (!$agentAdded)
109 {
110 $agentAdded = true;
111 $agents = \CAgent::GetList(array("ID" => "DESC"), array("NAME" => "\\Bitrix\\Main\\Data\\CacheEngineFiles::delayedDelete(%"));
112 if (!$agents->Fetch())
113 {
114 $res = \CAgent::AddAgent(
115 "\\Bitrix\\Main\\Data\\CacheEngineFiles::delayedDelete();",
116 "main", //module
117 "Y", //period
118 1 //interval
119 );
120
121 if (!$res)
122 $APPLICATION->ResetException();
123 }
124 }
125 }
126
135 private static function randomizeFile($fileName)
136 {
137 $documentRoot = Main\Loader::getDocumentRoot();
138 for ($i = 0; $i < 99; $i++)
139 {
140 $suffix = rand(0, 999999);
141 if (!file_exists($documentRoot.$fileName.$suffix))
142 return $fileName.$suffix;
143 }
144 return "";
145 }
146
156 public function clean($baseDir, $initDir = '', $filename = '')
157 {
158 $documentRoot = Main\Loader::getDocumentRoot();
159 if (($filename !== false) && ($filename !== ""))
160 {
161 static::unlink($documentRoot.$baseDir.$initDir.$filename);
162 }
163 else
164 {
165 $initDir = trim($initDir, "/");
166 if ($initDir == "")
167 {
168 $sourceDir = $documentRoot."/".trim($baseDir, "/");
169 if (file_exists($sourceDir) && is_dir($sourceDir))
170 {
171 $dh = opendir($sourceDir);
172 if (is_resource($dh))
173 {
174 while ($entry = readdir($dh))
175 {
176 if (preg_match("/^(\\.|\\.\\.|.*\\.~\\d+)\$/", $entry))
177 continue;
178
179 if (is_dir($sourceDir."/".$entry))
180 static::clean($baseDir, $entry);
181 elseif (is_file($sourceDir."/".$entry))
182 static::unlink($sourceDir."/".$entry);
183 }
184 }
185 }
186 }
187 else
188 {
189 $source = "/".trim($baseDir, "/")."/".$initDir;
190 $source = rtrim($source, "/");
191 $delayedDelete = false;
192
193 if (!preg_match("/^(\\.|\\.\\.|.*\\.~\\d+)\$/", $source) && file_exists($documentRoot.$source))
194 {
195 if (is_file($documentRoot.$source))
196 {
197 static::unlink($documentRoot.$source);
198 }
199 else
200 {
201 $target = static::randomizeFile($source.".~");
202 if ($target != '')
203 {
204 $con = Main\Application::getConnection();
205 $con->queryExecute("INSERT INTO b_cache_tag (SITE_ID, CACHE_SALT, RELATIVE_PATH, TAG) VALUES ('*', '*', '".$con->getSqlHelper()->forSql($target)."', '*')");
206 if (@rename($documentRoot.$source, $documentRoot.$target))
207 {
208 $delayedDelete = true;
209 }
210 }
211 }
212 }
213
214 if ($delayedDelete)
215 static::addAgent();
216 else
217 DeleteDirFilesEx($baseDir.$initDir);
218 }
219 }
220 }
221
230 protected function lock($fileName)
231 {
232 $wouldBlock = 0;
233 self::$lockHandles[$fileName] = @fopen($fileName, "r+");
234 if (self::$lockHandles[$fileName])
235 {
236 flock(self::$lockHandles[$fileName], LOCK_EX | LOCK_NB, $wouldBlock);
237 //$wouldBlock === 1 someone else has the lock.
238 }
239 return $wouldBlock !== 1;
240 }
241
249 protected function unlock($fileName)
250 {
251 if (self::$lockHandles[$fileName])
252 {
253 fclose(self::$lockHandles[$fileName]);
254 unset(self::$lockHandles[$fileName]);
255 }
256 }
257
269 public function read(&$vars, $baseDir, $initDir, $filename, $ttl)
270 {
271 $documentRoot = Main\Loader::getDocumentRoot();
272 $fn = $documentRoot."/".ltrim($baseDir.$initDir, "/").$filename;
273
274 if (!file_exists($fn))
275 return false;
276
277 $ser_content = "";
278 $dateexpire = 0;
279 $datecreate = 0;
280 $zeroDanger = false;
281
282 $handle = null;
283 if (is_array($vars))
284 {
285 $INCLUDE_FROM_CACHE = 'Y';
286
287 if (!@include($fn))
288 return false;
289 }
290 else
291 {
292 $handle = fopen($fn, "rb");
293 if (!$handle)
294 return false;
295
296 $datecreate = fread($handle, 2);
297 if ($datecreate == "BX")
298 {
299 $datecreate = fread($handle, 12);
300 $dateexpire = fread($handle, 12);
301 }
302 else
303 {
304 $datecreate .= fread($handle, 10);
305 }
306 }
307
308 /* We suppress warning here in order not to break the compression under Zend Server */
309 $this->read = @filesize($fn);
310 $this->path = $fn;
311
312 $res = true;
313 if (intval($datecreate) < (time() - $ttl))
314 {
315 if ($this->useLock)
316 {
317 if ($this->lock($fn))
318 {
319 $res = false;
320 }
321 }
322 else
323 {
324 $res = false;
325 }
326 }
327
328 if($res == true)
329 {
330 if (is_array($vars))
331 {
332 $vars = unserialize($ser_content);
333 }
334 else
335 {
336 $vars = fread($handle, $this->read);
337 }
338 }
339
340 if($handle)
341 {
342 fclose($handle);
343 }
344
345 return $res;
346 }
347
359 public function write($vars, $baseDir, $initDir, $filename, $ttl)
360 {
361 static $search = array("\\", "'", "\0");
362 static $replace = array("\\\\", "\\'", "'.chr(0).'");
363 $documentRoot = Main\Loader::getDocumentRoot();
364 $folder = $documentRoot."/".ltrim($baseDir.$initDir, "/");
365 $fn = $folder.$filename;
366 $fnTmp = $folder.md5(mt_rand()).".tmp";
367
368 if (!CheckDirPath($fn))
369 return;
370
371 if ($handle = fopen($fnTmp, "wb+"))
372 {
373 if (is_array($vars))
374 {
375 $contents = "<?";
376 $contents .= "\nif(\$INCLUDE_FROM_CACHE!='Y')return false;";
377 $contents .= "\n\$datecreate = '".str_pad(time(), 12, "0", STR_PAD_LEFT)."';";
378 $contents .= "\n\$dateexpire = '".str_pad(time() + intval($ttl), 12, "0", STR_PAD_LEFT)."';";
379 $contents .= "\n\$ser_content = '".str_replace($search, $replace, serialize($vars))."';";
380 $contents .= "\nreturn true;";
381 $contents .= "\n?>";
382 }
383 else
384 {
385 $contents = "BX".str_pad(time(), 12, "0", STR_PAD_LEFT).str_pad(time() + intval($this->ttl), 12, "0", STR_PAD_LEFT);
386 $contents .= $vars;
387 }
388
389 $this->written = fwrite($handle, $contents);
390 $this->path = $fn;
391 $len = strlen($contents);
392
393 fclose($handle);
394
395 static::unlink($fn);
396
397 if ($this->written === $len)
398 rename($fnTmp, $fn);
399
400 static::unlink($fnTmp);
401
402 if ($this->useLock)
403 {
404 $this->unlock($fn);
405 }
406 }
407 }
408
416 public function isCacheExpired($path)
417 {
418 if (!file_exists($path))
419 {
420 return true;
421 }
422
423 $fileHandler = fopen($path, "rb");
424 if ($fileHandler)
425 {
426 $header = fread($fileHandler, 150);
427 fclose($fileHandler);
428 }
429 else
430 {
431 return true;
432 }
433
434 if (
435 preg_match("/dateexpire\\s*=\\s*'([\\d]+)'/im", $header, $match)
436 || preg_match("/^BX\\d{12}(\\d{12})/", $header, $match)
437 || preg_match("/^(\\d{12})/", $header, $match)
438 )
439 {
440 if ($match[1] == '' || doubleval($match[1]) < time())
441 return true;
442 }
443
444 return false;
445 }
446
455 protected static function deleteOneDir($etime = 0, $ar = false)
456 {
457 $deleteFromQueue = false;
458 $dirName = Main\Loader::getDocumentRoot().$ar["RELATIVE_PATH"];
459 if ($ar["RELATIVE_PATH"] != '' && file_exists($dirName))
460 {
461 if (is_file($dirName))
462 {
463 DeleteDirFilesEx($ar["RELATIVE_PATH"]);
464 $deleteFromQueue = true;
465 }
466 else
467 {
468 $dh = opendir($dirName);
469 if (is_resource($dh))
470 {
471 $counter = 0;
472 while (($file = readdir($dh)) !== false)
473 {
474 if ($file != "." && $file != "..")
475 {
476 DeleteDirFilesEx($ar["RELATIVE_PATH"]."/".$file);
477 $counter++;
478 if (time() > $etime)
479 break;
480 }
481 }
482 closedir($dh);
483
484 if ($counter == 0)
485 {
486 rmdir($dirName);
487 $deleteFromQueue = true;
488 }
489 }
490 }
491 }
492 else
493 {
494 $deleteFromQueue = true;
495 }
496
497 if ($deleteFromQueue)
498 {
499 $con = Main\Application::getConnection();
500 $con->queryExecute("DELETE FROM b_cache_tag WHERE ID = ".intval($ar["ID"]));
501 }
502 }
503
511 public static function delayedDelete($count = 1)
512 {
513 $delta = 10;
514 $deleted = 0;
515 $etime = time() + 2;
516
517 $count = (int) $count;
518 if ($count < 1)
519 {
520 $count = 1;
521 }
522
523 $con = Main\Application::getConnection();
524 $rs = $con->query("SELECT * from b_cache_tag WHERE TAG='*'", 0, $count + $delta);
525 while ($ar = $rs->fetch())
526 {
527 $deleted++;
528 static::deleteOneDir($etime, $ar);
529
530 if (time() > $etime)
531 {
532 break;
533 }
534 }
535
536 if ($deleted > $count)
537 {
538 $count = $deleted;
539 }
540 elseif ($deleted < $count && $count > 1)
541 {
542 $count--;
543 }
544
545 if ($deleted > 0)
546 {
547 return "\\Bitrix\\Main\\Data\\CacheEngineFiles::delayedDelete(" . $count . ");";
548 }
549 else
550 {
551 return "";
552 }
553 }
554}
clean($baseDir, $initDir='', $filename='')
write($vars, $baseDir, $initDir, $filename, $ttl)
read(&$vars, $baseDir, $initDir, $filename, $ttl)
static deleteOneDir($etime=0, $ar=false)