1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
appcache.php
См. документацию.
1<?php
3
5use Bitrix\Main\Page\Asset;
6
8{
9
10 const MANIFEST_CHECK_FILE = "/bitrix/tools/check_appcache.php";
11 const DEBUG_HOLDER = "//__APP_CACHE_DEBUG_HOLDER__";
12 private static $debug;
13 private static $instance;
14 private static $isEnabled = false;
15 private static $customCheckFile = null;
16 private $files = Array();
17 private $pageURI = "";
18 private $network = Array();
19 private $fallbackPages = Array();
20 private $params = Array();
21 private $isSided = false;
22 private $isModified = false;
23 private $receivedManifest = "";
24 private $excludeImagePatterns= array();
25
26 private $receivedCacheParams = Array();
27
28 private function __construct()
29 {
30 //use \Bitrix\Main\Composite\AppCache::getInstance();
31 }
32
36 public static function getDebug()
37 {
38 return self::$debug;
39 }
40
44 public function isEnabled()
45 {
46 return self::$isEnabled;
47 }
48
53 public function getExcludeImagePatterns()
54 {
55 return $this->excludeImagePatterns;
56 }
57
62 public function setExcludeImagePatterns($excludeImagePatterns)
63 {
64 $this->excludeImagePatterns = $excludeImagePatterns;
65 }
66
67
68 private function __clone()
69 {
70 //you can't clone it
71
72 }
73
74 public static function getInstance()
75 {
76 if (is_null(self::$instance))
77 {
78 self::$instance = new static();
79 self::$debug = (defined("BX_APPCACHE_DEBUG") && BX_APPCACHE_DEBUG);
80 }
81
82 return self::$instance;
83 }
84
90 public static function setEnabled($isEnabled = true)
91 {
92 self::$isEnabled = (bool)$isEnabled;
93
94 }
95
96 public function generate(&$content)
97 {
98 $manifest = static::getInstance();
99 $files = $manifest->getFilesFromContent($content);
100
101 $this->isModified = false;
102 $manifestId = $this->getCurrentManifestID();
103
104 if ($this->isSided)
105 {
106 $curManifestId = $this->getManifestID($this->pageURI, $this->receivedCacheParams);
107 if ($curManifestId != $manifestId)
108 {
109 self::removeManifestById($curManifestId);
110 }
111 }
112
113 $currentHashSum = md5(serialize($files["FULL_FILE_LIST"]) . serialize($this->fallbackPages) . serialize($this->network) . serialize($this->excludeImagePatterns));
114 $manifestCache = $this->readManifestCache($manifestId);
115 if (!$manifestCache || $manifestCache["FILE_HASH"] != $currentHashSum || self::$debug)
116 {
117 $this->isModified = true;
118 $this->setFiles($files["FULL_FILE_LIST"]);
119 $this->setNetworkFiles(Array("*"));
121 "ID" => $manifestId,
122 "TEXT" => $this->getManifestContent(),
123 "FILE_HASH" => $currentHashSum,
124 "EXCLUDE_PATTERNS_HASH"=> md5(serialize($this->excludeImagePatterns)),
125 "FILE_DATA" => Array(
126 "FILE_TIMESTAMPS" => $files["FILE_TIMESTAMPS"],
127 "CSS_FILE_IMAGES" => $files["CSS_FILE_IMAGES"]
128 )
129 );
130
131 if (!self::$debug)
132 {
133 $this->writeManifestCache($arFields);
134 }
135 else
136 {
137 $jsFields = json_encode($arFields);
138 $fileCount = count($this->files);
139 $params = json_encode($this->params);
140 $fileCountImages = 0;
141 foreach ($arFields["FILE_DATA"]["CSS_FILE_IMAGES"] as $file=>$images)
142 {
143 if (is_array($images))
144 {
145 $fileCountImages += count($images);
146 }
147 }
148
149
150 $debugOutput = <<<JS
151
152 console.log("-------APPLICATION CACHE DEBUG INFO------");
153 console.log("File count:", $fileCount);
154 console.log("Image file count:", $fileCountImages);
155 console.log("Params:", $params);
156 console.log("Detail:", $jsFields);
157 console.log("--------------------------------------------");
158JS;
159
160 $jsContent = str_replace(array("\n", "\t"), "", $debugOutput);
161 $content = str_replace(self::DEBUG_HOLDER, $jsContent, $content);
162 }
163 }
164
165 return $this->getIsModified();
166 }
167
172 public static function onBeforeEndBufferContent()
173 {
174 global $APPLICATION;
175 $selfObject = self::getInstance();
176 $server = \Bitrix\Main\Context::getCurrent()->getServer();
177 $params = Array();
178 $appCacheUrl = $server->get("HTTP_BX_APPCACHE_URL");
179 $appCacheParams = $server->get("HTTP_BX_APPCACHE_PARAMS");
180 if ($appCacheUrl <> '')
181 {
182 //TODO compare $_SERVER["REQUEST_URI"] and $_SERVER["HTTP_BX_APPCACHE_URL"]
183 $selfObject->setIsSided(true);
184 $selfObject->setPageURI($appCacheUrl);
185 if ($appCacheParams)
186 {
187 $params = json_decode($appCacheParams, true);
188
189 if (!is_array($params))
190 {
191 $params = array();
192 }
193
194 $selfObject->setReceivedCacheParams($params);
195 }
196 }
197 else
198 {
199 $selfObject->setPageURI($server->get("REQUEST_URI"));
200
201 if(!self::$debug)
202 {
203 $APPLICATION->SetPageProperty("manifest", " manifest=\"" . self::getManifestCheckFile() . "?manifest_id=" . $selfObject->getCurrentManifestID() . "\"");
204 }
205 else
206 {
207 Asset::getInstance()->addString("<script>".self::DEBUG_HOLDER."</script>");
208 }
209
210 $params = Array(
211 "PAGE_URL" => $selfObject->getPageURI(),
212 "PARAMS" => $selfObject->getAdditionalParams(),
213 "MODE" => "APPCACHE"
214 );
215 }
216
217 return (is_array($params) ? $params : array());
218 }
219
224 public static function getManifestCheckFile()
225 {
226 $checkFile = self::MANIFEST_CHECK_FILE;
227 if(self::$customCheckFile != null && self::$customCheckFile <> '')
228 $checkFile = self::$customCheckFile;
229 return $checkFile;
230 }
231
237 public function setManifestCheckFile($customManifestCheckFile)
238 {
239 self::$customCheckFile = $customManifestCheckFile;
240 }
241
242 /*
243 * OnEndBufferContent handler
244 */
245 public static function onEndBufferContent(&$content)
246 {
247 static::getInstance()->generate($content);
248 }
249
254 public function getManifestContent()
255 {
256 $manifestText = "CACHE MANIFEST\n\n";
257 $manifestText .= $this->getManifestDescription();
258 $manifestText .= "#files" . "\n\n";
259 $manifestText .= implode("\n", $this->files) . "\n\n";
260 $manifestText .= "NETWORK:\n";
261 $manifestText .= implode("\n", $this->network) . "\n\n";
262 $manifestText .= "FALLBACK:\n\n";
263 $countFallback = count($this->fallbackPages);
264 for ($i = 0; $i < $countFallback; $i++)
265 {
266 $manifestText .= $this->fallbackPages[$i]["online"] . " " . $this->fallbackPages[$i]["offline"] . "\n";
267 }
268
269 return $manifestText;
270 }
271
280 {
281 $files = Array();
282 $arFilesByType = Array();
283 $arExtensions = Array("js", "css");
284 $extension_regex = "(?:" . implode("|", $arExtensions) . ")";
285 $findImageRegexp = "/
286 ((?i:
287 href=
288 |src=
289 |BX\\.loadCSS\\(
290 |BX\\.loadScript\\(
291 |jsUtils\\.loadJSFile\\(
292 |background\\s*:\\s*url\\(
293 )) #attribute
294 (\"|') #open_quote
295 ([^?'\"]+\\.) #href body
296 (" . $extension_regex . ") #extentions
297 (|\\?\\d+|\\?v=\\d+) #params
298 (\\2) #close_quote
299 /x";
300 $match = Array();
301 preg_match_all($findImageRegexp, $content, $match);
302
303 $link = $match[3];
304 $extension = $match[4];
305 $params = $match[5];
306 $linkCount = count($link);
307 $fileData = array(
308 "FULL_FILE_LIST" => array(),
309 "FILE_TIMESTAMPS" => array(),
310 "CSS_FILE_IMAGES" => array()
311 );
312 for ($i = 0; $i < $linkCount; $i++)
313 {
314 $fileData["FULL_FILE_LIST"][] = $files[] = $link[$i] . $extension[$i] . $params[$i];
315 $fileData["FILE_TIMESTAMPS"][$link[$i] . $extension[$i]] = $params[$i];
316 $arFilesByType[$extension[$i]][] = $link[$i] . $extension[$i];
317 }
318
319 $manifestCache = $this->readManifestCache($this->getCurrentManifestID());
320 $excludePatternsHash = md5(serialize($this->excludeImagePatterns));
321
322 if (array_key_exists("css", $arFilesByType))
323 {
324 $findImageRegexp = '#([;\s:]*(?:url|@import)\s*\‍(\s*)(\'|"|)(.+?)(\2)\s*\‍)#si';
325 if(!empty($this->excludeImagePatterns))
326 {
327 $findImageRegexp = '#([;\s:]*(?:url|@import)\s*\‍(\s*)(\'|"|)((?:(?!'.implode("|",$this->excludeImagePatterns).').)+?)(\2)\s*\‍)#si';
328 }
329
330 $cssCount = count($arFilesByType["css"]);
331 for ($j = 0; $j < $cssCount; $j++)
332 {
333 $cssFilePath = $arFilesByType["css"][$j];
334 if ($manifestCache["FILE_DATA"]["FILE_TIMESTAMPS"][$cssFilePath] != $fileData["FILE_TIMESTAMPS"][$cssFilePath]
335 ||$excludePatternsHash != $manifestCache["EXCLUDE_PATTERNS_HASH"]
336 )
337 {
338
339 $fileContent = false;
340 $fileUrl = parse_url($cssFilePath);
341 $file = new \Bitrix\Main\IO\File(Application::getDocumentRoot() . $fileUrl['path']);
342
343 if($file->getExtension() !== "css")
344 continue;
345
346 if ($file->isExists() && $file->isReadable())
347 {
348 $fileContent = $file->getContents();
349 }
350 elseif ($fileUrl["scheme"])
351 {
352 $http = new \Bitrix\Main\Web\HttpClient([
353 "socketTimeout" => 20,
354 "streamTimeout" => 20,
355 ]);
356 $fileContent = $http->get($cssFilePath);
357 }
358
359 if ($fileContent != false)
360 {
361 $cssFileRelative = new \Bitrix\Main\IO\File($cssFilePath);
362 $cssPath = $cssFileRelative->getDirectoryName();
363 preg_match_all($findImageRegexp, $fileContent, $match);
364 $matchCount = count($match[3]);
365 for ($k = 0; $k < $matchCount; $k++)
366 {
367
368 $file = self::replaceUrlCSS($match[3][$k], addslashes($cssPath));
369
370 if (!in_array($file, $files) && !mb_strpos($file, ";base64"))
371 {
372 $fileData["FULL_FILE_LIST"][] = $files[] = $file;
373 $fileData["CSS_FILE_IMAGES"][$cssFilePath][] = $file;
374 }
375 }
376 }
377 }
378 else
379 {
380 $fileData["CSS_FILE_IMAGES"][$cssFilePath] = $manifestCache["FILE_DATA"]["CSS_FILE_IMAGES"][$cssFilePath];
381 if (is_array($manifestCache["FILE_DATA"]["CSS_FILE_IMAGES"][$cssFilePath]))
382 {
383 $fileData["FULL_FILE_LIST"] = array_merge($fileData["FULL_FILE_LIST"], $manifestCache["FILE_DATA"]["CSS_FILE_IMAGES"][$cssFilePath]);
384 }
385 }
386
387 }
388 }
389
390 return $fileData;
391 }
392
401 private static function replaceUrlCSS($url, $cssPath)
402 {
403 if (str_contains($url, "://") || str_contains($url, "data:"))
404 {
405 return $url;
406 }
407 $url = trim(stripslashes($url), "'\" \r\n\t");
408 if (str_starts_with($url, "/"))
409 {
410 return $url;
411 }
412
413 return $cssPath . '/' . $url;
414 }
415
420 public function setReceivedCacheParams($receivedCacheParams)
421 {
422 $this->receivedCacheParams = $receivedCacheParams;
423 }
424
429 public function getReceivedCacheParams()
430 {
431 return $this->receivedCacheParams;
432 }
433
439 public function setReceivedManifest($receivedManifest)
440 {
441 $this->receivedManifest = $receivedManifest;
442 }
443
444 public function getReceivedManifest()
445 {
446 return $this->receivedManifest;
447 }
448
449 public function setIsSided($isSided)
450 {
451 $this->isSided = $isSided;
452 }
453
454 public function getIsSided()
455 {
456 return $this->isSided;
457 }
458
459 public function setPageURI($pageURI = "")
460 {
461 $this->pageURI = $pageURI;
462 }
463
464 public function getPageURI()
465 {
466 return $this->pageURI;
467 }
468
469 public function setFiles($arFiles)
470 {
471 if (!empty($this->files))
472 {
473 $this->files = array_merge($this->files, $arFiles);
474 }
475 else
476 {
477 $this->files = $arFiles;
478 }
479 }
480
481 public function addFile($filePath)
482 {
483 $this->files[] = $filePath;
484 }
485
486 public function addAdditionalParam($name, $value)
487 {
488 $this->params[$name] = $value;
489 }
490
491 public function getAdditionalParams()
492 {
493 return $this->params;
494 }
495
496 public function setNetworkFiles($network)
497 {
498 $this->network = $network;
499 }
500
501 public function getNetworkFiles()
502 {
503 return $this->network;
504 }
505
506 public function addFallbackPage($onlinePage, $offlinePage)
507 {
508 $this->fallbackPages[] = Array(
509 "online" => $onlinePage,
510 "offline" => $offlinePage
511 );
512 }
513
514 public function getFallbackPages()
515 {
516 return $this->fallbackPages;
517 }
518
519 public function getCurrentManifestID()
520 {
521 return $this->getManifestID($this->pageURI, $this->params);
522 }
523
524 public function getIsModified()
525 {
526 return $this->isModified && !self::$debug;
527 }
528
529 private function getManifestDescription()
530 {
531
532 $manifestParams = "";
533 $arCacheParams = $this->params;
534 if (!empty($arCacheParams))
535 {
536 foreach ($arCacheParams as $key => $value)
537 {
538 $manifestParams .= "#" . $key . "=" . $value . "\n";
539 }
540 }
541
542 $desc = "#Date: " . date("r") . "\n";
543 $desc .= "#Page: " . $this->pageURI . "\n";
544 $desc .= "#Count: " . count($this->files) . "\n";
545 $desc .= "#Params: \n" . $manifestParams . "\n\n";
546 $desc .= "#Exclude patterns: \n" . "#".implode("\n#",$this->getExcludeImagePatterns()) . "\n\n";
547
548 return $desc;
549 }
550
551 private function writeManifestCache($arFields)
552 {
553 $cache = new \CPHPCache();
554 $manifestId = $arFields["ID"];
555 $this->removeManifestById($manifestId);
556 $cachePath = self::getCachePath($manifestId);
557 $cache->StartDataCache(3600 * 24 * 365, $manifestId, $cachePath);
558 $cache->EndDataCache($arFields);
559
560 return true;
561 }
562
563 public static function readManifestCache($manifestId)
564 {
565 $cache = new \CPHPCache();
566
567 $cachePath = self::getCachePath($manifestId);
568 if ($cache->InitCache(3600 * 24 * 365, $manifestId, $cachePath))
569 {
570 return $cache->getVars();
571 }
572
573 return false;
574 }
575
576 private static function removeManifestById($manifestId)
577 {
578 $cache = new \CPHPCache();
579 $cachePath = self::getCachePath($manifestId);
580
581 $cache->CleanDir($cachePath);
582 }
583
589 public static function getCachePath($manifestId)
590 {
591 $cachePath = "/appcache/".mb_substr($manifestId, 0, 2)."/".mb_substr($manifestId, 2, 4) . "/";
592
593 return $cachePath;
594 }
595
596
597 private static function getManifestID($pageURI, $arParams)
598 {
599 $id = $pageURI;
600 if (!empty($arParams))
601 {
602 $strCacheParams = "";
603 foreach ($arParams as $key => $value)
604 {
605 $strCacheParams .= $key . "=" . $value;
606 }
607
608 $id .= $strCacheParams;
609 }
610
611 return md5($id);
612 }
613
614 public static function checkObsoleteManifest()
615 {
616 $server = \Bitrix\Main\Context::getCurrent()->getServer();
617 $appCacheUrl = $server->get("HTTP_BX_APPCACHE_URL");
618 $appCacheParams = $server->get("HTTP_BX_APPCACHE_PARAMS");
619 if ($appCacheUrl)
620 {
621 $params = json_decode($appCacheParams, true);
622
623 if (!is_array($params))
624 {
625 $params = array();
626 }
627
628 static::clear($appCacheUrl, $params);
629 }
630 }
631
632 private static function clear($url, $params)
633 {
634 $manifestId = self::getManifestID($url, $params);
635 if (self::readManifestCache($manifestId))
636 {
637 self::removeManifestById($manifestId);
638 self::getInstance()->isModified = true;
639 }
640
641 }
642
643}
644
645class_alias("Bitrix\\Main\\Composite\\AppCache", "Bitrix\\Main\\Data\\AppCacheManifest");
$arParams
Определения access_dialog.php:21
global $APPLICATION
Определения include.php:80
static getDocumentRoot()
Определения application.php:736
static getCachePath($manifestId)
Определения appcache.php:589
setExcludeImagePatterns($excludeImagePatterns)
Определения appcache.php:62
static onBeforeEndBufferContent()
Определения appcache.php:172
setIsSided($isSided)
Определения appcache.php:449
generate(&$content)
Определения appcache.php:96
getReceivedManifest()
Определения appcache.php:444
setPageURI($pageURI="")
Определения appcache.php:459
getReceivedCacheParams()
Определения appcache.php:429
setManifestCheckFile($customManifestCheckFile)
Определения appcache.php:237
addFile($filePath)
Определения appcache.php:481
getExcludeImagePatterns()
Определения appcache.php:53
const DEBUG_HOLDER
Определения appcache.php:11
static onEndBufferContent(&$content)
Определения appcache.php:245
const MANIFEST_CHECK_FILE
Определения appcache.php:10
setReceivedManifest($receivedManifest)
Определения appcache.php:439
static checkObsoleteManifest()
Определения appcache.php:614
addAdditionalParam($name, $value)
Определения appcache.php:486
addFallbackPage($onlinePage, $offlinePage)
Определения appcache.php:506
static getManifestCheckFile()
Определения appcache.php:224
static setEnabled($isEnabled=true)
Определения appcache.php:90
static getDebug()
Определения appcache.php:36
setReceivedCacheParams($receivedCacheParams)
Определения appcache.php:420
getAdditionalParams()
Определения appcache.php:491
static readManifestCache($manifestId)
Определения appcache.php:563
static getInstance()
Определения appcache.php:74
getFilesFromContent($content)
Определения appcache.php:279
setFiles($arFiles)
Определения appcache.php:469
getCurrentManifestID()
Определения appcache.php:519
setNetworkFiles($network)
Определения appcache.php:496
$content
Определения commerceml.php:144
$arFields
Определения dblapprove.php:5
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$fileContent
Определения file_property.php:47
$name
Определения menu_edit.php:35
if(mb_strlen($order)< 6) $desc
Определения payment.php:44
$arFiles
Определения options.php:60
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
if(empty($signedUserToken)) $key
Определения quickway.php:257
$i
Определения factura.php:643
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"
Определения waybill.php:936
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
Определения template.php:799
$k
Определения template_pdf.php:567
$url
Определения iframe.php:7