Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
manager.php
1<?php
2
11
21use Psr\Log;
22
28{
30 protected static $handlers = null;
31
33 protected static $data = [];
34
36 protected static $logErrors = false;
37
39 protected static $logger;
40
42 const INFO_NOT_AVAILABLE = null;
43
44 protected const CACHE_DIR = 'geoip_manager';
45
52 public static function getCountryCode($ip = '', $lang = '')
53 {
54 $resultData = self::getDataResult($ip, $lang, array('countryCode'));
55 return $resultData !== null ? $resultData->getGeoData()->countryCode : '';
56 }
57
64 public static function getCountryName($ip = '', $lang = '')
65 {
66 $resultData = self::getDataResult($ip, $lang, array('countryName'));
67 return $resultData !== null ? $resultData->getGeoData()->countryName : '';
68 }
69
76 public static function getCityName($ip = '', $lang = '')
77 {
78 $resultData = self::getDataResult($ip, $lang, array('cityName'));
79 return $resultData !== null ? $resultData->getGeoData()->cityName : '';
80 }
81
88 public static function getCityPostCode($ip = '', $lang = '')
89 {
90 $resultData = self::getDataResult($ip, $lang, array('zipCode'));
91 return $resultData !== null ? $resultData->getGeoData()->zipCode : '';
92 }
93
100 public static function getGeoPosition($ip = '', $lang = '')
101 {
102 $data = self::getDataResult($ip, $lang, array('latitude', 'longitude'));
103
104 if (
105 $data !== null
106 && $data->getGeoData()->latitude != null
107 && $data->getGeoData()->longitude != null
108 )
109 {
110 $result = Array(
111 'latitude' => $data->getGeoData()->latitude,
112 'longitude' => $data->getGeoData()->longitude,
113 );
114 }
115 else
116 {
117 $result = null;
118 }
119
120 return $result;
121 }
122
129 public static function getGeoPositionLatitude($ip = '', $lang = '')
130 {
131 $resultData = self::getDataResult($ip, $lang, array('latitude'));
132 return $resultData !== null ? $resultData->getGeoData()->latitude : '';
133 }
134
141 public static function getGeoPositionLongitude($ip = '', $lang = '')
142 {
143 $resultData = self::getDataResult($ip, $lang, array('longitude'));
144 return $resultData !== null ? $resultData->getGeoData()->longitude : '';
145 }
146
153 public static function getOrganizationName($ip = '', $lang = '')
154 {
155 $resultData = self::getDataResult($ip, $lang, array('organizationName'));
156 return $resultData !== null ? $resultData->getGeoData()->organizationName : '';
157 }
158
165 public static function getIspName($ip = '', $lang = '')
166 {
167 $resultData = self::getDataResult($ip, $lang, array('ispName'));
168 return $resultData !== null ? $resultData->getGeoData()->ispName : '';
169 }
170
177 public static function getTimezoneName($ip = '', $lang = '')
178 {
179 $resultData = self::getDataResult($ip, $lang, array('timezone'));
180 return $resultData !== null ? $resultData->getGeoData()->timezone : '';
181 }
182
191 public static function getDataResult($ip = '', $lang = '', array $required = [])
192 {
193 $result = null;
194
195 if ($ip == '')
196 {
197 $ip = self::getRealIp();
198 }
199
200 // cache on the hit
201 if (isset(self::$data[$ip][$lang]))
202 {
203 $data = self::$data[$ip][$lang];
204 if (empty($required) || self::hasDataAllRequiredFields($required, $data))
205 {
206 $result = ((new Result())->setGeoData($data));
207 }
208 }
209
210 if (!$result)
211 {
212 if(self::$handlers === null)
213 {
214 self::initHandlers();
215 }
216
217 foreach (self::$handlers as $class => $handler)
218 {
219 if (!$handler->isInstalled() || !$handler->isActive())
220 {
221 continue;
222 }
223
224 if ($lang != '' && !in_array($lang, $handler->getSupportedLanguages()))
225 {
226 continue;
227 }
228
229 if (!empty($required) && !self::hasDataAllRequiredFields($required, $handler->getProvidingData()))
230 {
231 continue;
232 }
233
234 $ipAddress = new Web\IpAddress($ip);
235
236 // get from cache
237 $records = self::getFromStore($ipAddress, $class);
238 $data = static::findForIp($ipAddress, $records, $lang);
239
240 if ($data)
241 {
242 if (empty($required) || self::hasDataAllRequiredFields($required, $data))
243 {
244 $data->ip = $ip;
245 self::$data[$ip][$lang] = $data;
246
247 $result = ((new Result())->setGeoData($data));
248 break;
249 }
250 }
251
252 $dataResult = $handler->getDataResult($ip, $lang);
253
254 if (!$dataResult)
255 {
256 continue;
257 }
258
259 if (!$dataResult->isSuccess())
260 {
261 if (self::$logErrors && ($logger = static::getLogger()))
262 {
263 $logger->error(
264 "{date} - {host}\nIP: {ip}, handler: {handler}, lang: {lang}\n{errors}\n{trace}{delimiter}\n",
265 [
266 'ip' => $ip,
267 'lang' => $lang,
268 'handler' => $handler->getId(),
269 'errors' => $dataResult->getErrorMessages(),
270 'trace' => Diag\Helper::getBackTrace(6, DEBUG_BACKTRACE_IGNORE_ARGS, 3),
271 ]
272 );
273 }
274
275 continue;
276 }
277
278 $data = $dataResult->getGeoData();
279 $data->handlerClass = $class;
280 $data->ip = $ip;
281
282 // write to cache
283 self::$data[$ip][$lang] = $data;
284 self::saveToStore($ipAddress, $records, $data, $lang);
285
286 // save geonames
287 if (Option::get('main', 'collect_geonames', 'N') == 'Y')
288 {
289 if (!empty($data->geonames))
290 {
291 Internal\GeonameTable::save($data->geonames);
292 }
293 }
294
295 $result = $dataResult;
296 break;
297 }
298 }
299
300 if ($result)
301 {
302 $event = new Event('main', 'onGeoIpGetResult', [
303 'originalData' => clone $result->getGeoData(),
304 'data' => $result->getGeoData(),
305 ]);
306 $event->send();
307 }
308
309 return $result;
310 }
311
312 protected static function getCacheId(Web\IpAddress $ipAddress, string $handler): string
313 {
314 return $ipAddress->toRange(24) . ':v1:' . $handler;
315 }
316
317 protected static function getFromStore(Web\IpAddress $ipAddress, string $handler): array
318 {
319 $cacheTtl = static::getCacheTtl();
320
321 if ($cacheTtl > 0)
322 {
323 $cache = Application::getInstance()->getManagedCache();
324 $cacheId = static::getCacheId($ipAddress, $handler);
325
326 if ($cache->read($cacheTtl, $cacheId, self::CACHE_DIR))
327 {
328 $records = $cache->get($cacheId);
329
330 if (is_array($records))
331 {
332 return $records;
333 }
334 }
335 }
336
337 return [];
338 }
339
340 protected static function findForIp(Web\IpAddress $ipAddress, array $records, string $lang): ?Data
341 {
342 foreach ($records as $range => $data)
343 {
344 if (isset($data[$lang]))
345 {
346 // sorted by the most specific first
347 if ($ipAddress->matchRange($range))
348 {
349 $result = new Data();
350
351 foreach ($data[$lang] as $attr => $value)
352 {
353 if (property_exists($result, $attr))
354 {
355 $result->$attr = $value;
356 }
357 }
358 return $result;
359 }
360 }
361 }
362 return null;
363 }
364
365 protected static function saveToStore(Web\IpAddress $ipAddress, array $records, Data $geoData, string $lang): void
366 {
367 $cacheTtl = static::getCacheTtl();
368
369 if ($cacheTtl > 0)
370 {
371 $storedData = [];
372 foreach (get_object_vars($geoData) as $attr => $value)
373 {
374 if ($value !== null)
375 {
376 $storedData[$attr] = $value;
377 }
378 }
379
380 $network = $geoData->ipNetwork ?? $ipAddress->toRange(32);
381 $records[$network][$lang] = $storedData;
382
383 // the most specific first
384 krsort($records);
385
386 $cache = Application::getInstance()->getManagedCache();
387 $cacheId = static::getCacheId($ipAddress, $geoData->handlerClass);
388
389 $cache->clean($cacheId, self::CACHE_DIR);
390 $cache->read($cacheTtl, $cacheId, self::CACHE_DIR);
391 $cache->set($cacheId, $records);
392 }
393 }
394
400 private static function hasDataAllRequiredFields(array $required, $geoData)
401 {
402 if(empty($required))
403 {
404 return true;
405 }
406
407 $vars = get_object_vars($geoData);
408
409 foreach($required as $field)
410 {
411 if($vars[$field] === null)
412 {
413 return false;
414 }
415 }
416
417 return true;
418 }
419
420 private static function initHandlers()
421 {
422 if(self::$handlers !== null)
423 return;
424
425 self::$handlers = array();
426 $handlersList = array();
427 $buildInHandlers = array(
428 '\Bitrix\Main\Service\GeoIp\GeoIP2' => 'lib/service/geoip/geoip2.php',
429 '\Bitrix\Main\Service\GeoIp\MaxMind' => 'lib/service/geoip/maxmind.php',
430 '\Bitrix\Main\Service\GeoIp\Extension' => 'lib/service/geoip/extension.php',
431 '\Bitrix\Main\Service\GeoIp\SypexGeo' => 'lib/service/geoip/sypexgeo.php'
432 );
433
434 Loader::registerAutoLoadClasses('main', $buildInHandlers);
435
436 $handlersFields = array();
437 $res = HandlerTable::getList(['cache' => ['ttl' => static::getCacheTtl()]]);
438
439 while($row = $res->fetch())
440 $handlersFields[$row['CLASS_NAME']] = $row;
441
442 foreach($buildInHandlers as $class => $file)
443 {
444 if(self::isHandlerClassValid($class))
445 {
446 $fields = $handlersFields[$class] ?? [];
447 $handlersList[$class] = new $class($fields);
448 $handlersSort[$class] = $handlersList[$class]->getSort();
449 }
450 }
451
452 $event = new Event('main', 'onMainGeoIpHandlersBuildList');
453 $event->send();
454 $resultList = $event->getResults();
455
456 if (is_array($resultList) && !empty($resultList))
457 {
458 $customClasses = array();
459
460 foreach ($resultList as $eventResult)
461 {
462 if ($eventResult->getType() != EventResult::SUCCESS)
463 continue;
464
465 $params = $eventResult->getParameters();
466
467 if(!empty($params) && is_array($params))
468 $customClasses = array_merge($customClasses, $params);
469 }
470
471 if(!empty($customClasses))
472 {
473 Loader::registerAutoLoadClasses(null, $customClasses);
474
475 foreach($customClasses as $class => $file)
476 {
477 if(!File::isFileExists(Application::getDocumentRoot().'/'.$file))
478 {
479 continue;
480 }
481
482 if(self::isHandlerClassValid($class))
483 {
484 $fields = $handlersFields[$class] ?? [];
485 $handlersList[$class] = new $class($fields);
486 $handlersSort[$class] = $handlersList[$class]->getSort();
487 }
488 }
489 }
490 }
491
492 asort($handlersSort, SORT_NUMERIC);
493
494 foreach($handlersSort as $class => $sort)
495 self::$handlers[$class] = $handlersList[$class];
496 }
497
502 private static function isHandlerClassValid($className)
503 {
504 if(!class_exists($className))
505 return false;
506
507 if(!is_subclass_of($className, '\Bitrix\Main\Service\GeoIp\Base'))
508 return false;
509
510 return true;
511 }
512
516 public static function getRealIp()
517 {
518 $ip = false;
519 $xForwarded = Application::getInstance()->getContext()->getServer()->get('HTTP_X_FORWARDED_FOR');
520
521 if (!empty($xForwarded))
522 {
523 $ips = explode (", ", $xForwarded);
524 $fCount = count($ips);
525
526 for ($i = 0; $i < $fCount; $i++)
527 {
528 if (!preg_match("/^(10|172\\.16|192\\.168)\\./", $ips[$i]))
529 {
530 $ip = $ips[$i];
531 break;
532 }
533 }
534 }
535
536 if(!$ip)
537 {
538 $ip = trim(Application::getInstance()->getContext()->getRequest()->getRemoteAddress());
539 }
540
541 return $ip;
542 }
543
548 public static function getHandlers()
549 {
550 if(self::$handlers === null)
551 self::initHandlers();
552
553 return self::$handlers;
554 }
555
560 public static function getHandlerByClassName($className)
561 {
562 if(self::$handlers === null)
563 self::initHandlers();
564
565 return self::$handlers[$className] ?? null;
566 }
567
572 public static function setLogErrors($isLog)
573 {
574 self::$logErrors = $isLog;
575 }
576
581 public static function getHandlerAdminConfigHtml(Base $handler)
582 {
583 $result = '';
584 $adminFields = $handler->getConfigForAdmin();
585
586 foreach ($adminFields as $field)
587 {
588 if ($field['TYPE'] == 'COLSPAN2')
589 {
590 $heading = isset($field['HEADING']) && $field['HEADING'] ? ' class="heading"' : '';
591 $result .= '<tr'.$heading.'><td colspan="2">'.$field['TITLE'];
592 }
593 elseif ($field['TYPE'] == 'TEXT' || $field['TYPE'] == 'CHECKBOX' || $field['TYPE'] == 'LIST')
594 {
595 $required = isset($field['REQUIRED']) && $field['REQUIRED'] ? ' class="adm-detail-required-field"' : '';
596 $disabled = isset($field['DISABLED']) && $field['DISABLED'] ? ' disabled' : '';
597 $value = isset($field['VALUE']) ? ' value="'.$field['VALUE'].'"' : '';
598 $name = isset($field['NAME']) ? ' name="'.$field['NAME'].'"' : '';
599 $title = isset($field['TITLE']) ? ' title="'.$field['TITLE'].'"' : '';
600
601 $result .= '<tr'.$required.'><td width="40%">'.$field['TITLE'].':</td><td width="60%">';
602
603 if ($field['TYPE'] == 'TEXT')
604 {
605 $result .= '<input type="text" size="45" maxlength="255"'.$name.$value.$disabled.$title.'>';
606 }
607 elseif ($field['TYPE'] == 'CHECKBOX')
608 {
609 $checked = isset($field['CHECKED']) && $field['CHECKED'] ? ' checked' : '';
610 $result .= '<input type="checkbox"'.$name.$value.$checked.$disabled.$title.'>';
611 }
612 else
613 {
614 $result .= '<select' . $name . $disabled . $title . '>';
615 if (is_array($field['OPTIONS']))
616 {
617 foreach ($field['OPTIONS'] as $key => $val)
618 {
619 $result .= '<option value="' . $key . '"' . ($key == $field['VALUE'] ? ' selected' : '') . '>' . $val . '</option>';
620 }
621 }
622 $result .= '</select>';
623 }
624 }
625
626 $result .= '</td></tr>';
627 }
628
629 return $result;
630 }
631
632 protected static function getCacheTtl(): int
633 {
634 static $cacheTtl = null;
635
636 if($cacheTtl === null)
637 {
638 $cacheFlags = Configuration::getValue('cache_flags');
639 $cacheTtl = $cacheFlags['geoip_manager'] ?? 604800; // a week
640 }
641 return $cacheTtl;
642 }
643
644 public static function cleanCache(): void
645 {
646 $cache = Application::getInstance()->getManagedCache();
647 $cache->cleanDir(static::CACHE_DIR);
648 }
649
650 protected static function getLogger()
651 {
652 if (static::$logger === null)
653 {
654 $logger = Diag\Logger::create('main.GeoIpManager');
655
656 if ($logger !== null)
657 {
658 static::$logger = $logger;
659 }
660 }
661
662 return static::$logger;
663 }
664}
static registerAutoLoadClasses($moduleName, array $classes)
Definition loader.php:273
static findForIp(Web\IpAddress $ipAddress, array $records, string $lang)
Definition manager.php:340
static getHandlerAdminConfigHtml(Base $handler)
Definition manager.php:581
static getOrganizationName($ip='', $lang='')
Definition manager.php:153
static getTimezoneName($ip='', $lang='')
Definition manager.php:177
static getCountryCode($ip='', $lang='')
Definition manager.php:52
static getDataResult($ip='', $lang='', array $required=[])
Definition manager.php:191
static getCountryName($ip='', $lang='')
Definition manager.php:64
static getGeoPosition($ip='', $lang='')
Definition manager.php:100
static getCityName($ip='', $lang='')
Definition manager.php:76
static getGeoPositionLatitude($ip='', $lang='')
Definition manager.php:129
static saveToStore(Web\IpAddress $ipAddress, array $records, Data $geoData, string $lang)
Definition manager.php:365
static getIspName($ip='', $lang='')
Definition manager.php:165
static getCacheId(Web\IpAddress $ipAddress, string $handler)
Definition manager.php:312
static getGeoPositionLongitude($ip='', $lang='')
Definition manager.php:141
static getCityPostCode($ip='', $lang='')
Definition manager.php:88
static getHandlerByClassName($className)
Definition manager.php:560
static getFromStore(Web\IpAddress $ipAddress, string $handler)
Definition manager.php:317