1C-Bitrix 25.700.0
Загрузка...
Поиск...
Не найдено
manager.php
См. документацию.
1<?php
2
9
10namespace Bitrix\Main\Service\GeoIp;
11
12use Bitrix\Main\Application;
13use Bitrix\Main\Context;
14use Bitrix\Main\Event;
15use Bitrix\Main\IO\File;
16use Bitrix\Main\Loader;
17use Bitrix\Main\EventResult;
18use Bitrix\Main\Config\Configuration;
19use Bitrix\Main\Config\Option;
20use Bitrix\Main\Web\IpAddress;
21use Bitrix\Main\Diag;
22use Psr\Log;
23
29{
31 const INFO_NOT_AVAILABLE = null;
32 protected const CACHE_DIR = 'geoip_manager';
33
35 protected static $handlers = null;
37 protected static $data = [];
39 protected static $logErrors = false;
41 protected static $logger;
42
49 public static function getCountryCode($ip = '', $lang = '')
50 {
51 $resultData = self::getDataResult($ip, $lang, ['countryCode']);
52 return $resultData !== null ? $resultData->getGeoData()->countryCode : '';
53 }
54
61 public static function getCountryName($ip = '', $lang = '')
62 {
63 $resultData = self::getDataResult($ip, $lang, ['countryName']);
64 return $resultData !== null ? $resultData->getGeoData()->countryName : '';
65 }
66
73 public static function getCityName($ip = '', $lang = '')
74 {
75 $resultData = self::getDataResult($ip, $lang, ['cityName']);
76 return $resultData !== null ? $resultData->getGeoData()->cityName : '';
77 }
78
85 public static function getCityPostCode($ip = '', $lang = '')
86 {
87 $resultData = self::getDataResult($ip, $lang, ['zipCode']);
88 return $resultData !== null ? $resultData->getGeoData()->zipCode : '';
89 }
90
97 public static function getGeoPosition($ip = '', $lang = '')
98 {
99 $data = self::getDataResult($ip, $lang, ['latitude', 'longitude']);
100
101 if (
102 $data !== null
103 && $data->getGeoData()->latitude != null
104 && $data->getGeoData()->longitude != null
105 )
106 {
107 $result = [
108 'latitude' => $data->getGeoData()->latitude,
109 'longitude' => $data->getGeoData()->longitude,
110 ];
111 }
112 else
113 {
114 $result = null;
115 }
116
117 return $result;
118 }
119
126 public static function getGeoPositionLatitude($ip = '', $lang = '')
127 {
128 $resultData = self::getDataResult($ip, $lang, ['latitude']);
129 return $resultData !== null ? $resultData->getGeoData()->latitude : '';
130 }
131
138 public static function getGeoPositionLongitude($ip = '', $lang = '')
139 {
140 $resultData = self::getDataResult($ip, $lang, ['longitude']);
141 return $resultData !== null ? $resultData->getGeoData()->longitude : '';
142 }
143
150 public static function getOrganizationName($ip = '', $lang = '')
151 {
152 $resultData = self::getDataResult($ip, $lang, ['organizationName']);
153 return $resultData !== null ? $resultData->getGeoData()->organizationName : '';
154 }
155
162 public static function getIspName($ip = '', $lang = '')
163 {
164 $resultData = self::getDataResult($ip, $lang, ['ispName']);
165 return $resultData !== null ? $resultData->getGeoData()->ispName : '';
166 }
167
174 public static function getTimezoneName($ip = '', $lang = '')
175 {
176 $resultData = self::getDataResult($ip, $lang, ['timezone']);
177 return $resultData !== null ? $resultData->getGeoData()->timezone : '';
178 }
179
188 public static function getDataResult($ip = '', $lang = '', array $required = [])
189 {
190 $result = null;
191
192 if ($ip == '')
193 {
194 $ip = self::getRealIp();
195 }
196
197 // cache on the hit
198 if (isset(self::$data[$ip][$lang]))
199 {
200 $data = self::$data[$ip][$lang];
201 if (empty($required) || self::hasDataAllRequiredFields($required, $data))
202 {
203 $result = ((new Result())->setGeoData($data));
204 }
205 }
206
207 if (!$result)
208 {
209 if (self::$handlers === null)
210 {
211 self::initHandlers();
212 }
213
214 foreach (self::$handlers as $class => $handler)
215 {
216 if (!$handler->isInstalled() || !$handler->isActive())
217 {
218 continue;
219 }
220
221 if ($lang != '' && !in_array($lang, $handler->getSupportedLanguages()))
222 {
223 continue;
224 }
225
226 if (!empty($required) && !self::hasDataAllRequiredFields($required, $handler->getProvidingData()))
227 {
228 continue;
229 }
230
231 $ipAddress = new IpAddress($ip);
232
233 // get from cache
234 $records = self::getFromStore($ipAddress, $class);
235 $data = static::findForIp($ipAddress, $records, $lang);
236
237 if ($data)
238 {
239 if (empty($required) || self::hasDataAllRequiredFields($required, $data))
240 {
241 $data->ip = $ip;
242 self::$data[$ip][$lang] = $data;
243
244 $result = ((new Result())->setGeoData($data));
245 break;
246 }
247 }
248
249 $dataResult = $handler->getDataResult($ip, $lang);
250
251 if (!$dataResult)
252 {
253 continue;
254 }
255
256 if (!$dataResult->isSuccess())
257 {
258 if (self::$logErrors && ($logger = static::getLogger()))
259 {
260 $logger->error(
261 "{date} - {host}\nIP: {ip}, handler: {handler}, lang: {lang}\n{errors}\n{trace}{delimiter}\n",
262 [
263 'ip' => $ip,
264 'lang' => $lang,
265 'handler' => $handler->getId(),
266 'errors' => $dataResult->getErrorMessages(),
267 'trace' => Diag\Helper::getBackTrace(6, DEBUG_BACKTRACE_IGNORE_ARGS, 3),
268 ]
269 );
270 }
271
272 continue;
273 }
274
275 $data = $dataResult->getGeoData();
276 $data->handlerClass = $class;
277 $data->ip = $ip;
278
279 // write to cache
280 self::$data[$ip][$lang] = $data;
281 self::saveToStore($ipAddress, $records, $data, $lang);
282
283 // save geonames
284 if (Option::get('main', 'collect_geonames', 'N') == 'Y')
285 {
286 if (!empty($data->geonames))
287 {
289 }
290 }
291
292 $result = $dataResult;
293 break;
294 }
295 }
296
297 if ($result)
298 {
299 $event = new Event('main', 'onGeoIpGetResult', [
300 'originalData' => clone $result->getGeoData(),
301 'data' => $result->getGeoData(),
302 ]);
303 $event->send();
304 }
305
306 return $result;
307 }
308
309 protected static function getCacheId(IpAddress $ipAddress, string $handler): string
310 {
311 return $ipAddress->toRange(24) . ':v1:' . $handler;
312 }
313
314 protected static function getFromStore(IpAddress $ipAddress, string $handler): array
315 {
316 if (!$ipAddress->isIPv4())
317 {
318 return [];
319 }
320
321 $cacheTtl = static::getCacheTtl();
322
323 if ($cacheTtl > 0)
324 {
325 $cache = Application::getInstance()->getManagedCache();
326 $cacheId = static::getCacheId($ipAddress, $handler);
327
328 if ($cache->read($cacheTtl, $cacheId, self::CACHE_DIR))
329 {
330 $records = $cache->get($cacheId);
331
332 if (is_array($records))
333 {
334 return $records;
335 }
336 }
337 }
338
339 return [];
340 }
341
342 protected static function findForIp(IpAddress $ipAddress, array $records, string $lang): ?Data
343 {
344 foreach ($records as $range => $data)
345 {
346 if (isset($data[$lang]))
347 {
348 // sorted by the most specific first
349 if ($ipAddress->matchRange($range))
350 {
351 $result = new Data();
352
353 foreach ($data[$lang] as $attr => $value)
354 {
355 if (property_exists($result, $attr))
356 {
357 $result->$attr = $value;
358 }
359 }
360 return $result;
361 }
362 }
363 }
364 return null;
365 }
366
367 protected static function saveToStore(IpAddress $ipAddress, array $records, Data $geoData, string $lang): void
368 {
369 if (!$ipAddress->isIPv4())
370 {
371 return;
372 }
373
374 $cacheTtl = static::getCacheTtl();
375
376 if ($cacheTtl > 0)
377 {
378 $storedData = array_filter(get_object_vars($geoData), function ($value) {
379 return $value !== null;
380 });
381
382 $network = $geoData->ipNetwork ?? $ipAddress->toRange(32);
383 $records[$network][$lang] = $storedData;
384
385 // the most specific first
386 krsort($records);
387
388 $cache = Application::getInstance()->getManagedCache();
389 $cacheId = static::getCacheId($ipAddress, $geoData->handlerClass);
390
391 $cache->clean($cacheId, self::CACHE_DIR);
392 $cache->read($cacheTtl, $cacheId, self::CACHE_DIR);
393 $cache->set($cacheId, $records);
394 }
395 }
396
402 private static function hasDataAllRequiredFields(array $required, $geoData)
403 {
404 if (empty($required))
405 {
406 return true;
407 }
408
409 $vars = get_object_vars($geoData);
410
411 foreach ($required as $field)
412 {
413 if ($vars[$field] === null)
414 {
415 return false;
416 }
417 }
418
419 return true;
420 }
421
422 private static function initHandlers()
423 {
424 if (self::$handlers !== null)
425 {
426 return;
427 }
428
429 self::$handlers = [];
430 $handlersList = [];
431 $buildInHandlers = [
432 '\Bitrix\Main\Service\GeoIp\GeoIP2' => 'lib/service/geoip/geoip2.php',
433 '\Bitrix\Main\Service\GeoIp\MaxMind' => 'lib/service/geoip/maxmind.php',
434 '\Bitrix\Main\Service\GeoIp\Extension' => 'lib/service/geoip/extension.php',
435 '\Bitrix\Main\Service\GeoIp\SypexGeo' => 'lib/service/geoip/sypexgeo.php',
436 ];
437
438 Loader::registerAutoLoadClasses('main', $buildInHandlers);
439
440 $handlersFields = [];
441 $res = HandlerTable::getList(['cache' => ['ttl' => static::getCacheTtl()]]);
442
443 while ($row = $res->fetch())
444 {
445 $handlersFields[$row['CLASS_NAME']] = $row;
446 }
447
448 foreach ($buildInHandlers as $class => $file)
449 {
450 if (self::isHandlerClassValid($class))
451 {
452 $fields = $handlersFields[$class] ?? [];
453 $handlersList[$class] = new $class($fields);
454 $handlersSort[$class] = $handlersList[$class]->getSort();
455 }
456 }
457
458 $event = new Event('main', 'onMainGeoIpHandlersBuildList');
459 $event->send();
460 $resultList = $event->getResults();
461
462 if (is_array($resultList) && !empty($resultList))
463 {
464 $customClasses = [];
465
466 foreach ($resultList as $eventResult)
467 {
468 if ($eventResult->getType() != EventResult::SUCCESS)
469 {
470 continue;
471 }
472
473 $params = $eventResult->getParameters();
474
475 if (!empty($params) && is_array($params))
476 {
477 $customClasses = array_merge($customClasses, $params);
478 }
479 }
480
481 if (!empty($customClasses))
482 {
483 Loader::registerAutoLoadClasses(null, $customClasses);
484
485 foreach ($customClasses as $class => $file)
486 {
487 if (!File::isFileExists(Application::getDocumentRoot() . '/' . $file))
488 {
489 continue;
490 }
491
492 if (self::isHandlerClassValid($class))
493 {
494 $fields = $handlersFields[$class] ?? [];
495 $handlersList[$class] = new $class($fields);
496 $handlersSort[$class] = $handlersList[$class]->getSort();
497 }
498 }
499 }
500 }
501
502 asort($handlersSort, SORT_NUMERIC);
503
504 foreach ($handlersSort as $class => $sort)
505 {
506 self::$handlers[$class] = $handlersList[$class];
507 }
508 }
509
514 private static function isHandlerClassValid($className)
515 {
516 if (!class_exists($className))
517 {
518 return false;
519 }
520
521 if (!is_subclass_of($className, '\Bitrix\Main\Service\GeoIp\Base'))
522 {
523 return false;
524 }
525
526 return true;
527 }
528
532 public static function getRealIp()
533 {
534 $context = Context::getCurrent();
535 $xForwarded = $context->getServer()->get('HTTP_X_FORWARDED_FOR');
536
537 if (!empty($xForwarded))
538 {
539 $ips = explode(", ", $xForwarded);
540
541 foreach ($ips as $forwarded)
542 {
543 $ipAddress = new IPAddress($forwarded);
544 if ($ipAddress->isIPv4() && !$ipAddress->isPrivate())
545 {
546 return (string)$ipAddress;
547 }
548 }
549 }
550
551 return trim($context->getRequest()->getRemoteAddress());
552 }
553
557
558 public static function getHandlers()
559 {
560 if (self::$handlers === null)
561 {
562 self::initHandlers();
563 }
564
565 return self::$handlers;
566 }
567
572 public static function getHandlerByClassName($className)
573 {
574 if (self::$handlers === null)
575 {
576 self::initHandlers();
577 }
578
579 return self::$handlers[$className] ?? null;
580 }
581
586 public static function setLogErrors($isLog)
587 {
588 self::$logErrors = $isLog;
589 }
590
595 public static function getHandlerAdminConfigHtml(Base $handler)
596 {
597 $result = '';
598 $adminFields = $handler->getConfigForAdmin();
599
600 foreach ($adminFields as $field)
601 {
602 if ($field['TYPE'] == 'COLSPAN2')
603 {
604 $heading = isset($field['HEADING']) && $field['HEADING'] ? ' class="heading"' : '';
605 $result .= '<tr' . $heading . '><td colspan="2">' . $field['TITLE'];
606 }
607 elseif ($field['TYPE'] == 'TEXT' || $field['TYPE'] == 'CHECKBOX' || $field['TYPE'] == 'LIST')
608 {
609 $required = isset($field['REQUIRED']) && $field['REQUIRED'] ? ' class="adm-detail-required-field"' : '';
610 $disabled = isset($field['DISABLED']) && $field['DISABLED'] ? ' disabled' : '';
611 $value = isset($field['VALUE']) ? ' value="' . $field['VALUE'] . '"' : '';
612 $name = isset($field['NAME']) ? ' name="' . $field['NAME'] . '"' : '';
613 $title = isset($field['TITLE']) ? ' title="' . $field['TITLE'] . '"' : '';
614
615 $result .= '<tr' . $required . '><td width="40%">' . $field['TITLE'] . ':</td><td width="60%">';
616
617 if ($field['TYPE'] == 'TEXT')
618 {
619 $result .= '<input type="text" size="45" maxlength="255"' . $name . $value . $disabled . $title . '>';
620 }
621 elseif ($field['TYPE'] == 'CHECKBOX')
622 {
623 $checked = isset($field['CHECKED']) && $field['CHECKED'] ? ' checked' : '';
624 $result .= '<input type="checkbox"' . $name . $value . $checked . $disabled . $title . '>';
625 }
626 else
627 {
628 $result .= '<select' . $name . $disabled . $title . '>';
629 if (is_array($field['OPTIONS']))
630 {
631 foreach ($field['OPTIONS'] as $key => $val)
632 {
633 $result .= '<option value="' . $key . '"' . ($key == $field['VALUE'] ? ' selected' : '') . '>' . $val . '</option>';
634 }
635 }
636 $result .= '</select>';
637 }
638 }
639
640 $result .= '</td></tr>';
641 }
642
643 return $result;
644 }
645
646 protected static function getCacheTtl(): int
647 {
648 $cacheFlags = Configuration::getValue('cache_flags');
649 return $cacheFlags['geoip_manager'] ?? 604800; // a week
650 }
651
652 public static function cleanCache(): void
653 {
654 $cache = Application::getInstance()->getManagedCache();
655 $cache->cleanDir(static::CACHE_DIR);
656 }
657
658 protected static function getLogger()
659 {
660 if (static::$logger === null)
661 {
662 $logger = Diag\Logger::create('main.GeoIpManager');
663
664 if ($logger !== null)
665 {
666 static::$logger = $logger;
667 }
668 }
669
670 return static::$logger;
671 }
672}
static getDocumentRoot()
Определения application.php:736
static getInstance()
Определения application.php:98
Определения result.php:20
static create(string $id, $params=[])
Определения logger.php:121
Определения event.php:5
static registerAutoLoadClasses($moduleName, array $classes)
Определения loader.php:273
static getList(array $parameters=array())
Определения datamanager.php:431
getConfigForAdmin()
Определения base.php:92
static getHandlerAdminConfigHtml(Base $handler)
Определения manager.php:595
static getOrganizationName($ip='', $lang='')
Определения manager.php:150
static $logErrors
Определения manager.php:39
static saveToStore(IpAddress $ipAddress, array $records, Data $geoData, string $lang)
Определения manager.php:367
static getHandlers()
Определения manager.php:558
static cleanCache()
Определения manager.php:652
static getCacheId(IpAddress $ipAddress, string $handler)
Определения manager.php:309
static getTimezoneName($ip='', $lang='')
Определения manager.php:174
static getCountryCode($ip='', $lang='')
Определения manager.php:49
static getDataResult($ip='', $lang='', array $required=[])
Определения manager.php:188
static getFromStore(IpAddress $ipAddress, string $handler)
Определения manager.php:314
static getCountryName($ip='', $lang='')
Определения manager.php:61
static getGeoPosition($ip='', $lang='')
Определения manager.php:97
static getCityName($ip='', $lang='')
Определения manager.php:73
static getLogger()
Определения manager.php:658
static getGeoPositionLatitude($ip='', $lang='')
Определения manager.php:126
const CACHE_DIR
Определения manager.php:32
static getRealIp()
Определения manager.php:532
static $handlers
Определения manager.php:35
static getIspName($ip='', $lang='')
Определения manager.php:162
static getGeoPositionLongitude($ip='', $lang='')
Определения manager.php:138
static getCityPostCode($ip='', $lang='')
Определения manager.php:85
static findForIp(IpAddress $ipAddress, array $records, string $lang)
Определения manager.php:342
static getCacheTtl()
Определения manager.php:646
static $logger
Определения manager.php:41
static getHandlerByClassName($className)
Определения manager.php:572
const INFO_NOT_AVAILABLE
Определения manager.php:31
static setLogErrors($isLog)
Определения manager.php:586
toRange(int $prefixLen)
Определения ipaddress.php:124
matchRange(string $cidr)
Определения ipaddress.php:95
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
Определения file_new.php:804
$res
Определения filter_act.php:7
$result
Определения get_property_values.php:14
$context
Определения csv_new_setup.php:223
if(!defined('SITE_ID')) $lang
Определения include.php:91
$name
Определения menu_edit.php:35
Определения aliases.php:105
Определения cachetracker.php:2
$event
Определения prolog_after.php:141
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
Определения prolog_main_admin.php:393
$storedData
Определения quickway.php:285
if(empty($signedUserToken)) $key
Определения quickway.php:257
if($inWords) echo htmlspecialcharsbx(Number2Word_Rus(roundEx($totalVatSum $params['CURRENCY']
Определения template.php:799
$title
Определения pdf.php:123
$val
Определения options.php:1793
$fields
Определения yandex_run.php:501