xorgxx/neox-geolocator-bundle

Neox 地理定位组件包,适用于 Symfony

0.6.4 2023-12-14 09:37 UTC

This package is auto-updated.

Last update: 2024-09-25 07:59:46 UTC


README

本组件包提供额外的地理定位工具,旨在简化您在应用中管理这些工具的过程,并作为防火墙使用!

2023-11-28-22-27-57.png

假设您不希望来自“南美洲”的用户访问您的应用,或者不希望使用 Vpn、代理、Tor 的用户访问,或者您只想允许来自“巴黎”的用户访问。地理定位正是您需要的解决方案!即使无法过滤移动设备,如果所有过滤条件都返回“Seo_unauthorized”,则不会允许访问您的网站。

BETA 版本安装!!

使用 Composer 安装组件包,因为它目前处于 beta 版本!!

  composer require xorgxx/neox-geolocator-bundle
  or 
  composer require xorgxx/neox-geolocator-bundle:0.*

确保在您的 AppKernel 中注册了组件包

Bundles.php
<?php

return [
    .....
    NeoxGeolocator\NeoxGeolocatorBundle\NeoxGeolocatorBundle::class => ['all' => true],
    .....
];

注意: 您可能需要使用 [symfony composer dump-autoload] 来重新加载自动加载

..... 完成 🎈

配置

  • 安装和配置 ==> Symfony 配置
  • 在配置文件夹中创建 neox_geolocator.yaml
└─── config
│   └─── packages
│       └─── neox_geolocator.yaml
|       └─── ..... 

neox_seo.yaml

自动设置,但您可以自定义(默认)

   neox_geolocator:
      ip_local_dev: "156.146.55.226" # for test  Bulgary "156.146.55.226"
      forcer: false # this is to force to get new geolocator same timer it's userfull.
      check_ping:  # false | true it will protect agains "death ping" !!!
          on: false       # on off
          expire: 10      # check expiration to reste timer
          ping:   5       # after x ping on "expire" value it will banni for xxx
          banni: 700      # in seconde banni time
      cdn:
          api_use: "findip.net" # ip-api.com freemium,  check.getipintel.net FREE, https://findip.net/ free
          api_key: "xxxxxxxxxxxxxxxxxx"
      filter:
          # Local how can in website | rule order read = 1
          local:
              - 'FR'
              - 'BG'
   
          # Continents how can in website | rule order read = 2
          continents:
              - "Europe"
              - "North America"
      #            - "South America"
      #            - "Asia"  
          # Connection how cant in website !!! | rule order read = 3
          connection:
              - "vpn"
              - "proxy"
              
      # Crawler how can in website !! | rule order read = 4
      crawler:
          - "Googlebot"
          - "Bingbot"
          - "YandexBot"
          - "AppleBot"
          - "DuckDuckBot"
          - "BaiduSpider"
          - "SpiderSogou"
          - "FacebookExternalHit"
          - "Exabot"
          - "Swiftbot"
          - "SlurpBot"
          - "CCBot"
          - "GoogleOther"
          - "Google-InspectionTool"
          
      name_route_exclude:     # all this name-route will be excluded form the geolocator !!!
          - "Seo_unauthorized"
          - "app_home_profile_crud_alert"  
          
      name_route_unauthorized: "Seo_unauthorized"
      timer: 10
      check_vpn: "seo_check_vpn" >>> name route to redirect when detect no id session yet 

如何使用?

  • 非常简单!
  • 请注意,我使用 Redis 存储会话信息,这可能会对您的应用产生影响。
  • 缓存系统,设置 expirAfter 确保键在 xx 后过期,并强制再次控制。

只需创建路由和模板到 name_route_unauthorized: "Seo_unauthorized"

    /**
     * @Route("/unauthorized", name="Seo_unauthorized")
     * @param Request $request
     * @return Response
     */
     
    #[NeoxGeoBag( forcer: true, filterLocal: ["RU", "GB"], filterContinents: ["Asia"])]   
    public function unauthorized(Request $request, CacheItemPoolInterface  $adapter): Response
    {
        $session    = $request->getSession();
        $Geolocator = $adapter->getItem(geolocatorAbstract::NAME . $session->getId());
        $metadata   = $Geolocator->getMetadata();
        
        if ( $Geolocator && $Geolocator->isHit() && array_key_exists('expiry', $metadata)) {
            $expirationTimestamp    = $metadata['expiry'];
            $expirationDateTime     = $date = new DateTime("@$expirationTimestamp");
        };
        
        $i = $Geolocator->get("value");
        return $this->render('unauthorized.html.twig', [
            "Geolocator"        => $Geolocator->get("value"),
            "timer"             => $expirationDateTime ?? null,
        ]);
    }
    {% block HEADERSLIDER %}
    
        <section id="slider" class="slider-element min-vh-100 page-section slide-img include-header"
                 data-animate="img-to-right"
                 style="background: url('{{ imgErrorBackg }}') center center no-repeat; background-size: cover;">
            <div class="slider-inner">
                <div class="vertical-middle">
    
                	<div class="container-fluid clearfix vertical-middle" style="z-index: 6">
					<div class="heading-block center topmargin nobottomborder">

						{% if Geolocator is not null %}
							<i style="line-height:unset !important;"
							   class="fa-2xl fi fi-{{ Geolocator.countryCode|lower == 'en' ? 'gb' : Geolocator.countryCode|lower }}"></i>
							{% if Geolocator.valid %}
								<h1>{{ 'unauthorized.title'|trans }} </h1>
								<span><i class="{{ Geolocator.valid ? 'text-success' : 'text-danger' }} fa-solid {{ Geolocator.valid ? 'fa-check-square' : 'fa-window-close' }}"></i> <strong>{{ Geolocator.country }}</strong>, {{ Geolocator.city }}</span>

							{% else %}
								<h1>{{ 'unauthorized.fail.title'|trans }} </h1>
								<span><i class="{{ Geolocator.valid ? 'text-success' : 'text-danger' }} fa-solid {{ Geolocator.valid ? 'fa-check-square' : 'fa-window-close' }}"></i> <strong>{{ Geolocator.country }}</strong>, {{ Geolocator.city }}</span>
								{% if Geolocator.proxy|default(0) %}
									<span><i class="{{ Geolocator.proxy|default(0) ? 'text-danger' : 'text-success' }} fa-solid {{ Geolocator.proxy|default(0) ? 'fa-window-close' : 'fa-check-square' }}"></i> Proxy / Vpn / Tor : {{ Geolocator.proxy|default(0) ? 'Detecté !' : ' - ' }}</span>
								{% endif %}
								<span>{{ 'unauthorized.fail.subtitle'|trans }}</span>

								<div class="row justify-content-center col-mb-50">
									<div class="col-sm-6 col-lg-4">
									</div>

									<div class="col-sm-6 col-lg-4">
										<div class="feature-box fbox-center fbox-light fbox-plain">
											<div class="fbox-icon">
												<a href="#"><i class="icon-time"></i></a>
											</div>
											<div class="fbox-content">
												<h3>{{ 'unauthorized.title-time'|trans |raw }}</h3>
												<p>{{ 'unauthorized.subtitle-time'|trans |raw }}</p>
											</div>
										</div>
									</div>
								</div>
							{% endif %}
							<small>- {{ timer|format_datetime('short', timezone='Europe/Paris') }} -</small>

						{% else %}
							<span><i class="text-danger fa-solid fa-window-close"></i> Proxy / Vpn / Tor : Detecté !</span>
						{% endif %}
					</div>

				</div>
            </div>
            </div>
        </section>
    {% endblock %}

示例:twig check_vpn

    .....
    
    {% block javascripts  %}
        <script>
         // Wait 0.5 seconds (500 milliseconds) then redirect
            setTimeout(function() {
                window.location.href = "/";
            }, 500);
        </script>
   
    {% endblock %}

高级用法

  • 您有自己的地理位置服务提供商?没问题
   neox_geolocator:
      ....
      custome_api: app\services\IpApiService # path to your file
      ....

此文件具有以下结构

    namespace App\Services;
    
    use NeoxGeolocator\NeoxGeolocatorBundle\Entity\Geolocation;
    use NeoxGeolocator\NeoxGeolocatorBundle\Pattern\geolocatorAbstract;
    use NeoxGeolocator\NeoxGeolocatorBundle\Pattern\GeolocatorInterface;
    use Psr\Cache\InvalidArgumentException;
    use Symfony\Component\Cache\Adapter\FilesystemAdapter;
    use Symfony\Component\Cache\CacheItem;
    use Symfony\Contracts\Cache\ItemInterface;
    use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
    use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
    use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
    use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
    
    class ipApiService extends geolocatorAbstract implements GeolocatorInterface
    {
        public function Geolocator(): Geolocation
        {
            
            // get geolocation
            $this->Geolocation = $this->getInfoCdn();
            
            // set filter Local
            $this->setFilterLocal();
            
            // set filter contement
            $this->setFilterContinents();
            
            // set filter Connection
            $this->setFilterConnection();
            
            // set crawler
            $this->setFilterCrawler();
            
//            $this->requestStack->getSession()->set('geolocator', $this->Geolocation);
            
            return $this->Geolocation;
            
            // TODO: Implement Geolocator() method.
        }
        
        public function getInfoCdn(): Geolocation{
            
            // check ip
            // $currentIp = $ipCheck ?: $this->httpClient->request('GET', $this->CDN["ip"] )->getContent();
            // $currentIp      = $this->requestStack->getCurrentRequest()->getClientIp();
            $data   = "";
            if ( $this->getLimiter('ipapi') ) {
                $currentIp      = $this->getRealIp();
                $api            = "http://" . $this->neoxBag->getCdn()["api_use"] . "/json/$currentIp?fields=status,message,continent,continentCode,country,countryCode,regionName,city,zip,lat,lon,reverse,mobile,proxy,hosting,query";
                // todo: check if this expires !!!
                $response_      = $this->httpClient->request('GET', $api );
                $data           = $response_->getContent();
                
                # for adaptation data 2 options
                # FIRST OPTION
                return Geolocation::fromJson($data); 
                
                # SECOND OPTION
                $geolocation   = new Geolocation();
                    $geolocationModel->setstatus('success')               // = ;
                    ->setcontinent($o["continent"]["names"]["fr"])          // = 'Europe';
                    ->setcontinentCode($o["continent"]["code"])             // = 'EU';
                    ->setcountry($o["country"]["names"]["en"])              // = 'France';
                    ->setcountryCode($o["country"]["iso_code"])             // = 'FR';
                    ->setregionName($o["subdivisions"][0]["names"]["en"])   // = 'Paris';
                    ->setcity($o["city"]["names"]["en"])                    // = 'Paris';
                    ->setzip($o["postal"]["code"])                          // = '75000';
                    ->setlat($o["location"]["latitude"])                    // = 40.6951;
                    ->setlon($o["location"]["longitude"])                   // = 20.325;
                    ->setreverse($o["traits"]["isp"])                       // = 'unn-156-146-55-226.cdn';
                    ->setmobile('nc')                                 // = false;
                    ->setproxy(($o["traits"]["connection_type"] == 'Corporate' ? true : false))     // = false;
                    ->sethosting(($o["traits"]["user_type"] == 'hosting' ? true : false))           // = false;
                    ->setquery($currentIp)           // = '156.146.55.226';
                    ->setvalid(true)            // = true;
                ;
            
              return $geolocation;
            }else{
                /** @var geolocatorAbstract $class */
                $class = $this->buildClass("findIpService");
                return  $class->Geolocator();
            }
        }
    }
  • 在 3 个事件上添加事件监听器

      const NEOX_GEOLOCATOR_EVENT     = 'neox.geolocator.event';
      const NEOX_GEOLOCATOR_PASS      = 'neox.geolocator.pass';
      const NEOX_GEOLOCATOR_FAIL      = 'neox.geolocator.fail';
    

因此现在您可以在您的应用中创建自己的统计方法!在 App\EventSubscriber 中

<?php
    
    namespace App\EventSubscriber;
    
    use NeoxGeolocator\NeoxGeolocatorBundle\Event\NeoxGeolocatorEvents;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    
    class NeoxGeolocatorSubscriber implements EventSubscriberInterface
    {
        
        /**
         * @inheritDoc
         */
        public static function getSubscribedEvents(): array
        {
            return [
                NeoxGeolocatorEvents::NEOX_GEOLOCATOR_EVENT => 'onCustomEvent',
                NeoxGeolocatorEvents::NEOX_GEOLOCATOR_PASS  => 'onCustomEvent',
                NeoxGeolocatorEvents::NEOX_GEOLOCATOR_FAIL  => 'onCustomEvent',
            ];
        }
        
        public function onCustomEvent(NeoxGeolocatorEvents $event): void
        {
            // Faire quelque chose avec l'événement
            $neoxGeolocation = $event->getGeolocation();
            ......
        }
    }

工具!

贡献

如果您想为此组件包做出贡献(感谢您!)请参考以下指南

  • 请遵守 Symfony 指南
  • 测试一切!请在上传测试案例到 tests/ 目录时
    • 修复了一个之前未涵盖的 bug
    • 注解!!

待办事项

  • Packagist

谢谢