1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
responder.php
См. документацию.
1<?
2namespace Bitrix\Main\Composite;
3
4use Bitrix\Main\Composite\Debug\Logger;
5
11{
12 private static $error = null;
13 private static $errorMessage = null;
19 public static function respond()
20 {
21 require_once(__DIR__."/helper.php");
22
23 self::setErrorHandler(); //avoid possible PHP warnings or notices
24 self::registerAutoloader();
25
26 self::modifyHttpHeaders();
27
28 if (self::isValidRequest())
29 {
30 if (!Helper::isCompositeRequest())
31 {
32 self::trySendResponse();
33 }
34
35 define("USE_HTML_STATIC_CACHE", true);
36 }
37
38 self::unregisterAutoloader();
39 self::restoreErrorHandler();
40 }
41
42 private static function isValidRequest()
43 {
44 if (
45 isset($_SERVER["HTTP_BX_AJAX"]) ||
46 isset($_GET["bxajaxid"]) ||
47 (isset($_SERVER["HTTP_X_REQUESTED_WITH"]) && $_SERVER["HTTP_X_REQUESTED_WITH"] === "XMLHttpRequest")
48 )
49 {
50 self::$error = Logger::TYPE_AJAX_REQUEST;
51 return false;
52 }
53
54 if (isset($_GET["ncc"]))
55 {
56 self::$error = Logger::TYPE_NCC_PARAMETER;
57 return false;
58 }
59
60 if (Helper::isBitrixFolder())
61 {
62 self::$error = Logger::TYPE_BITRIX_FOLDER;
63 return false;
64 }
65
66 if (preg_match("#^/index_controller\\.php#", $_SERVER["REQUEST_URI"]) > 0)
67 {
68 self::$error = Logger::TYPE_CONTROLLER_FILE;
69 return false;
70 }
71
72 //to warm up localStorage
73 define("ENABLE_HTML_STATIC_CACHE_JS", true);
74
75 if ($_SERVER["REQUEST_METHOD"] !== "GET")
76 {
77 self::$error = Logger::TYPE_GET_METHOD_ONLY;
78 self::$errorMessage = "Request Method: ".$_SERVER["REQUEST_METHOD"];
79 return false;
80 }
81
82 if (isset($_GET["sessid"]))
83 {
84 self::$error = Logger::TYPE_SESSID_PARAMETER;
85 return false;
86 }
87
88 $compositeOptions = Helper::getOptions();
89
90 //NCC cookie exists
91 if (isset($compositeOptions["COOKIE_NCC"]) &&
92 array_key_exists($compositeOptions["COOKIE_NCC"], $_COOKIE) &&
93 $_COOKIE[$compositeOptions["COOKIE_NCC"]] === "Y"
94 )
95 {
96 self::$error = Logger::TYPE_NCC_COOKIE;
97 return false;
98 }
99
100 //A stored authorization exists, but CC cookie doesn't exist
101 if (
102 isset($compositeOptions["STORE_PASSWORD"]) &&
103 $compositeOptions["STORE_PASSWORD"] == "Y" &&
104 isset($_COOKIE[$compositeOptions["COOKIE_LOGIN"]]) &&
105 $_COOKIE[$compositeOptions["COOKIE_LOGIN"]] !== "" &&
106 isset($_COOKIE[$compositeOptions["COOKIE_PASS"]]) &&
107 $_COOKIE[$compositeOptions["COOKIE_PASS"]] !== ""
108 )
109 {
110 if (
111 !isset($compositeOptions["COOKIE_CC"]) ||
112 !array_key_exists($compositeOptions["COOKIE_CC"], $_COOKIE) ||
113 $_COOKIE[$compositeOptions["COOKIE_CC"]] !== "Y"
114 )
115 {
116 self::$error = Logger::TYPE_CC_COOKIE_NOT_FOUND;
117 return false;
118 }
119 }
120
121 $queryPos = mb_strpos($_SERVER["REQUEST_URI"], "?");
122 $requestUri = $queryPos === false? $_SERVER["REQUEST_URI"] : mb_substr($_SERVER["REQUEST_URI"], 0, $queryPos);
123
124 //Checks excluded masks
125 if (isset($compositeOptions["~EXCLUDE_MASK"]) && is_array($compositeOptions["~EXCLUDE_MASK"]))
126 {
127 foreach ($compositeOptions["~EXCLUDE_MASK"] as $mask)
128 {
129 if (preg_match($mask, $requestUri) > 0)
130 {
131 self::$error = Logger::TYPE_EXCLUDE_MASK;
132 self::$errorMessage = "Mask: ".$mask;
133 return false;
134 }
135 }
136 }
137
138 //Checks excluded GET params
139 if (isset($compositeOptions["~EXCLUDE_PARAMS"]) && is_array($compositeOptions["~EXCLUDE_PARAMS"]))
140 {
141 foreach ($compositeOptions["~EXCLUDE_PARAMS"] as $param)
142 {
143 if (array_key_exists($param, $_GET))
144 {
145 self::$error = Logger::TYPE_EXCLUDE_PARAMETER;
146 self::$errorMessage = "Parameter: ".$param;
147 return false;
148 }
149 }
150 }
151
152 //Checks included masks
153 $isRequestInMask = false;
154 if (isset($compositeOptions["~INCLUDE_MASK"]) && is_array($compositeOptions["~INCLUDE_MASK"]))
155 {
156 foreach ($compositeOptions["~INCLUDE_MASK"] as $mask)
157 {
158 if (preg_match($mask, $requestUri) > 0)
159 {
160 $isRequestInMask = true;
161 break;
162 }
163 }
164 }
165
166 if (!$isRequestInMask)
167 {
168 self::$error = Logger::TYPE_INCLUDE_MASK;
169 return false;
170 }
171
172 //Checks hosts
173 $host = Helper::getHttpHost();
174 if (!in_array($host, Helper::getDomains()))
175 {
176 self::$error = Logger::TYPE_INVALID_HOST;
177 self::$errorMessage = "Host: ".$host;
178 return false;
179 }
180
181 if (!self::isValidQueryString($compositeOptions))
182 {
183 self::$error = Logger::TYPE_INVALID_QUERY_STRING;
184 return false;
185 }
186
187 return true;
188 }
189
193 private static function trySendResponse()
194 {
195 $cacheKey = self::getCacheKey();
196 $cache = self::getHtmlCacheResponse($cacheKey);
197 if ($cache === null || !$cache->exists())
198 {
199 return;
200 }
201
202 $compositeOptions = Helper::getOptions();
203
204 $etag = $cache->getEtag();
205 $lastModified = $cache->getLastModified();
206 if ($etag !== false)
207 {
208 if (array_key_exists("HTTP_IF_NONE_MATCH", $_SERVER) && $_SERVER["HTTP_IF_NONE_MATCH"] === $etag)
209 {
210 self::setStatus("304 Not Modified");
211 self::setHeaders($etag, false, "304");
212 die();
213 }
214 }
215
216 if ($lastModified !== false)
217 {
218 $sinceModified =
219 isset($_SERVER["HTTP_IF_MODIFIED_SINCE"]) ?
220 strtotime($_SERVER["HTTP_IF_MODIFIED_SINCE"]) :
221 false;
222
223 if ($sinceModified && $sinceModified >= $lastModified)
224 {
225 self::setStatus("304 Not Modified");
226 self::setHeaders($etag, false, "304");
227 die();
228 }
229 }
230
231 $contents = $cache->getContents();
232 if ($contents !== false)
233 {
234 self::setHeaders($etag, $lastModified, "200", $cache->getContentType());
235
236 //compression support
237 $compress = "";
238 if ($compositeOptions["COMPRESS"] && isset($_SERVER["HTTP_ACCEPT_ENCODING"]))
239 {
240 if (str_contains($_SERVER["HTTP_ACCEPT_ENCODING"], "x-gzip"))
241 {
242 $compress = "x-gzip";
243 }
244 elseif (str_contains($_SERVER["HTTP_ACCEPT_ENCODING"], "gzip"))
245 {
246 $compress = "gzip";
247 }
248 }
249
250 if ($compress)
251 {
252 header("Content-Encoding: ".$compress);
253 echo $cache->isGzipped() ? $contents : gzencode($contents, 4);
254 }
255 else
256 {
257 if ($cache->isGzipped())
258 {
259 $contents = Helper::gzdecode($contents);
260 }
261
262 header("Content-Length: " . strlen($contents));
263 echo $contents;
264 }
265
266 die();
267 }
268 }
269
270 private static function modifyHttpHeaders()
271 {
272 Helper::removeRandParam();
273
274 if (isset($_SERVER["HTTP_BX_REF"]))
275 {
276 $_SERVER["HTTP_REFERER"] = $_SERVER["HTTP_BX_REF"];
277 }
278 }
279
289 private static function setHeaders($etag, $lastModified, $compositeHeader = false, $contentType = false)
290 {
291 if ($etag !== false)
292 {
293 header("ETag: ".$etag);
294 }
295
296 header("Expires: Fri, 07 Jun 1974 04:00:00 GMT");
297
298 if ($lastModified !== false)
299 {
300 $utc = gmdate("D, d M Y H:i:s", $lastModified)." GMT";
301 header("Last-Modified: ".$utc);
302 }
303
304 if ($contentType !== false)
305 {
306 header("Content-type: ".$contentType);
307 }
308
309 if ($compositeHeader !== false)
310 {
311 header("X-Bitrix-Composite: Cache (".$compositeHeader.")");
312 }
313 }
314
320 private static function setStatus($status)
321 {
322 $bCgi = (mb_stristr(php_sapi_name(), "cgi") !== false);
323 $bFastCgi = ($bCgi && (array_key_exists("FCGI_ROLE", $_SERVER) || array_key_exists("FCGI_ROLE", $_ENV)));
324 if ($bCgi && !$bFastCgi)
325 {
326 header("Status: ".$status);
327 }
328 else
329 {
330 header($_SERVER["SERVER_PROTOCOL"]." ".$status);
331 }
332 }
333
334 private static function isValidQueryString($compositeOptions)
335 {
336 if (!isset($compositeOptions["INDEX_ONLY"]) || !$compositeOptions["INDEX_ONLY"])
337 {
338 return true;
339 }
340
341 $queryString = "";
342 if (isset($_SERVER["REQUEST_URI"]) && ($position = mb_strpos($_SERVER["REQUEST_URI"], "?")) !== false)
343 {
344 $queryString = mb_substr($_SERVER["REQUEST_URI"], $position + 1);
345 $queryString = Helper::removeIgnoredParams($queryString);
346 }
347
348 if ($queryString === "")
349 {
350 return true;
351 }
352
353 $queryParams = array();
354 parse_str($queryString, $queryParams);
355 if (isset($compositeOptions["~GET"]) &&
356 !empty($compositeOptions["~GET"]) &&
357 empty(array_diff(array_keys($queryParams), $compositeOptions["~GET"]))
358 )
359 {
360 return true;
361 }
362
363 return false;
364 }
365
371 private static function getCacheKey()
372 {
373 $userPrivateKey = Helper::getUserPrivateKey();
374
375 return Helper::convertUriToPath(
376 Helper::getRequestUri(),
377 Helper::getHttpHost(),
378 Helper::getRealPrivateKey($userPrivateKey)
379 );
380 }
381
389 private static function getHtmlCacheResponse($cacheKey)
390 {
391 $configuration = array();
392 $compositeOptions = Helper::getOptions();
393 $storage = $compositeOptions["STORAGE"] ?? false;
394 if (in_array($storage, array("memcached", "memcached_cluster")))
395 {
396 if (extension_loaded("memcache"))
397 {
398 return new MemcachedResponse($cacheKey, $configuration, $compositeOptions);
399 }
400 else
401 {
402 return null;
403 }
404 }
405 else
406 {
407 return new FileResponse($cacheKey, $configuration, $compositeOptions);
408 }
409 }
410
411 private static function registerAutoloader()
412 {
413 \spl_autoload_register(array(__CLASS__, "autoLoad"), true);
414 }
415
416 private static function unregisterAutoloader()
417 {
418 \spl_autoload_unregister(array(__CLASS__, "autoLoad"));
419 }
420
421 public static function autoLoad($className)
422 {
423 $className = ltrim($className, "\\"); // fix web env
424 if ($className === "Bitrix\\Main\\Composite\\Debug\\Logger")
425 {
426 require_once(__DIR__."/debug/logger.php");
427 }
428 }
429
435 public static function getLastError()
436 {
437 return self::$error;
438 }
439
445 public static function getLastErrorMessage()
446 {
447 return self::$errorMessage;
448 }
449
450 private static function setErrorHandler()
451 {
452 set_error_handler(array(__CLASS__, "handleError"));
453 }
454
455 private static function restoreErrorHandler()
456 {
457 restore_error_handler();
458 }
459
460 public static function handleError($code, $message, $file, $line)
461 {
462 return true;
463 }
464}
465
470abstract class AbstractResponse
471{
472 protected $cacheKey = null;
473 protected $configuration = array();
475
482 {
483 $this->cacheKey = $cacheKey;
484 $this->configuration = $configuration;
485 $this->htmlCacheOptions = $htmlCacheOptions;
486 }
487
492 abstract public function getContents();
493
498 abstract public function isGzipped();
499
504 abstract public function getLastModified();
505
510 abstract public function getEtag();
511
516 abstract public function getContentType();
517
523 abstract public function exists();
524
529 abstract public function shouldCountQuota();
530}
531
533{
537 private $props = null;
538
542 private static $memcached = null;
543 private static $connected = null;
544 private $contents = null;
545 private $flags = 0;
546
547 const MEMCACHED_GZIP_FLAG = 65536;
548
554
555 public function getContents()
556 {
557 if (self::$memcached === null)
558 {
559 return false;
560 }
561
562 if ($this->contents === null)
563 {
564 $this->contents = self::$memcached->get($this->cacheKey, $this->flags);
565 }
566
567 return $this->contents;
568 }
569
570 public function getLastModified()
571 {
572 return $this->getProp("mtime");
573 }
574
575 public function getEtag()
576 {
577 return $this->getProp("etag");
578 }
579
580 public function getContentType()
581 {
582 return $this->getProp("type");
583 }
584
585 public function exists()
586 {
587 return $this->getProps() !== false;
588 }
589
594 public function isGzipped()
595 {
596 $this->getContents();
597
598 return ($this->flags & self::MEMCACHED_GZIP_FLAG) === self::MEMCACHED_GZIP_FLAG;
599 }
600
605 public function shouldCountQuota()
606 {
607 return false;
608 }
609
615 private static function getServers(array $htmlCacheOptions)
616 {
617 $arServers = array();
618 if ($htmlCacheOptions["STORAGE"] === "memcached_cluster")
619 {
620 $groupId = $htmlCacheOptions["MEMCACHED_CLUSTER_GROUP"] ?? 1;
621 $arServers = self::getClusterServers($groupId);
622 }
623 elseif (isset($htmlCacheOptions["MEMCACHED_HOST"]) && isset($htmlCacheOptions["MEMCACHED_PORT"]))
624 {
625 $arServers[] = array(
626 "HOST" => $htmlCacheOptions["MEMCACHED_HOST"],
627 "PORT" => $htmlCacheOptions["MEMCACHED_PORT"]
628 );
629 }
630
631 return $arServers;
632 }
633
641 private static function getClusterServers($groupId)
642 {
643 $arServers = array();
644
645 $arList = false;
646 if (file_exists($_SERVER["DOCUMENT_ROOT"].BX_ROOT."/modules/cluster/memcache.php"))
647 {
648 include($_SERVER["DOCUMENT_ROOT"].BX_ROOT."/modules/cluster/memcache.php");
649 }
650
651 if (defined("BX_MEMCACHE_CLUSTER") && is_array($arList))
652 {
653 foreach ($arList as $arServer)
654 {
655 if ($arServer["STATUS"] === "ONLINE" && $arServer["GROUP_ID"] == $groupId)
656 {
657 $arServers[] = $arServer;
658 }
659 }
660 }
661
662 return $arServers;
663 }
664
674 {
675 if (self::$memcached === null && self::$connected === null)
676 {
677 $arServers = self::getServers($htmlCacheOptions);
678 $memcached = new \Memcache;
679 if (count($arServers) === 1)
680 {
681 if ($memcached->connect($arServers[0]["HOST"], $arServers[0]["PORT"]))
682 {
683 self::$connected = true;
684 self::$memcached = $memcached;
685 register_shutdown_function(array(__CLASS__, "close"));
686 }
687 else
688 {
689 self::$connected = false;
690 }
691 }
692 elseif (count($arServers) > 1)
693 {
694 self::$memcached = $memcached;
695 foreach ($arServers as $arServer)
696 {
697 self::$memcached->addServer(
698 $arServer["HOST"],
699 $arServer["PORT"],
700 true, //persistent
701 ($arServer["WEIGHT"] > 0 ? $arServer["WEIGHT"] : 1),
702 1 //timeout
703 );
704 }
705 }
706 else
707 {
708 self::$connected = false;
709 }
710 }
711
712 return self::$memcached;
713 }
714
718 public static function close()
719 {
720 if (self::$memcached !== null)
721 {
722 self::$memcached->close();
723 self::$memcached = null;
724 }
725 }
726
732 public function getProps()
733 {
734 if ($this->props === null)
735 {
736 if (self::$memcached !== null)
737 {
738 $props = self::$memcached->get("~".$this->cacheKey);
739 $this->props = is_object($props) ? $props : false;
740 }
741 else
742 {
743 $this->props = false;
744 }
745 }
746
747 return $this->props;
748 }
749
757 public function getProp($property)
758 {
759 $props = $this->getProps();
760 if ($props !== false && isset($props->{$property}))
761 {
762 return $props->{$property};
763 }
764
765 return false;
766 }
767}
768
770{
771 private $cacheFile = null;
772 private $lastModified = null;
773 private $contents = null;
774
776 {
777 parent::__construct($cacheKey, $configuration, $htmlCacheOptions);
778 $pagesPath = $_SERVER["DOCUMENT_ROOT"].BX_PERSONAL_ROOT."/html_pages";
779
780 if (file_exists($pagesPath.$this->cacheKey))
781 {
782 $this->cacheFile = $pagesPath.$this->cacheKey;
783 }
784 }
785
786 public function getContents()
787 {
788 if ($this->cacheFile === null)
789 {
790 return false;
791 }
792
793 if ($this->contents === null)
794 {
795 $this->contents = file_get_contents($this->cacheFile);
796 if ($this->contents !== false &&
797 (mb_strlen($this->contents) < 2500 || !preg_match("/^[a-f0-9]{32}$/", mb_substr($this->contents, -35, 32)))
798 )
799 {
800 $this->contents = false;
801 }
802 }
803
804 return $this->contents;
805 }
806
807 public function getLastModified()
808 {
809 if ($this->cacheFile === null)
810 {
811 return false;
812 }
813
814 if ($this->lastModified === null)
815 {
816 $this->lastModified = filemtime($this->cacheFile);
817 }
818
819 return $this->lastModified;
820
821 }
822
823 public function getEtag()
824 {
825 if ($this->cacheFile === null)
826 {
827 return false;
828 }
829
830 return md5(
831 $this->cacheFile.filesize($this->cacheFile).$this->getLastModified()
832 );
833 }
834
835 public function getContentType()
836 {
837 $contents = $this->getContents();
838 $head = mb_strpos($contents, "</head>");
839 $meta = "#<meta.*?charset\\s*=\\s*(?:[\"']?)([^\"'>]+)#im";
840
841 if ($head !== false && preg_match($meta, mb_substr($contents, 0, $head), $match))
842 {
843 return "text/html; charset=".$match[1];
844 }
845
846 return false;
847 }
848
849 public function exists()
850 {
851 return $this->cacheFile !== null;
852 }
853
858 public function shouldCountQuota()
859 {
860 return true;
861 }
862
867 public function isGzipped()
868 {
869 return false;
870 }
871}
872
873class_alias("Bitrix\\Main\\Composite\\AbstractResponse", "StaticHtmlCacheResponse");
874class_alias("Bitrix\\Main\\Composite\\MemcachedResponse", "StaticHtmlMemcachedResponse");
875class_alias("Bitrix\\Main\\Composite\\FileResponse", "StaticHtmlFileResponse");
const BX_ROOT
Определения bx_root.php:3
__construct($cacheKey, array $configuration, array $htmlCacheOptions)
Определения responder.php:481
__construct($cacheKey, array $configuration, array $htmlCacheOptions)
Определения responder.php:775
static getConnection(array $configuration, array $htmlCacheOptions)
Определения responder.php:673
__construct($cacheKey, array $configuration, array $htmlCacheOptions)
Определения responder.php:549
static getLastErrorMessage()
Определения responder.php:445
static getLastError()
Определения responder.php:435
static respond()
Определения responder.php:19
static autoLoad($className)
Определения responder.php:421
static handleError($code, $message, $file, $line)
Определения responder.php:460
$contents
Определения commerceml2.php:57
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$_SERVER["DOCUMENT_ROOT"]
Определения cron_frame.php:9
if(!is_null($config))($config as $configItem)(! $configItem->isVisible()) $code
Определения options.php:195
$requestUri
Определения urlrewrite.php:51
$status
Определения session.php:10
$host
Определения mysql_to_pgsql.php:32
$message
Определения payment.php:8
return false
Определения prolog_main_admin.php:185
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
die
Определения quickway.php:367
$contentType
Определения quickway.php:301
if(empty($decryptedData)) $storage
Определения quickway.php:270
</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
$props
Определения template.php:269