germania-kg/ipstack-client

支持 PSR-6 缓存和 Slim3 中间件的 ipstack API PHP 客户端

1.4.7 2022-05-30 13:45 UTC

README

支持缓存和中间件的 ipstack API PHP 客户端

Packagist PHP version Build Status Scrutinizer Code Quality Code Coverage Build Status

安装

$ composer require germania-kg/ipstack

使用 ipstack

<?php
use Germania\IpstackClient\IpstackClient;

// Setup the Client
$endpoint  = "http://api.ipstack.com/";
$api_key   = "your_api_key";
$ipstack   = new IpstackClient( $endpoint, $api_key);

// Ask ipstack
$client_ip = "8.8.8.8";
$response  = $ipstack->get( $client_ip );

响应示例

IpstackClient 内部使用数组,因此要求 ipstack 返回 JSON。以下是一个简化的示例;完整示例请参见 ipstack 的 标准 IP 查询 文档

Array ()
  [ip] => 8.8.8.8
  [type] => ipv4
  [continent_code] => EU
  [continent_name] => Europe
  [country_code] => DE
  [country_name] => Germany
  [region_code] => SH
  [region_name] => Schleswig-Holstein
  [latitude] => 54.3667
  [longitude] => 10.2
  ...
)

自定义响应

您可以通过在底层请求中添加某些字段来自定义 ipstack 响应,具体请参见 ipstack 在 “指定响应字段” 上的文档。只需传递一个包含查询字段的数组,这些字段将被添加到 GET 请求中

$response = $ipstack->get( "8.8.8.8", array(
  'language' => "de",
  'fields'   => "ip,country_code,country_name,latitude,longitude,region_name"
));

缓存 ipstack 响应

如果您正在使用每月限制为 10,000 次请求的 ipstack 免费计划,您可能希望通过将查找结果保存到 PSR-6 缓存来节省请求。 IpstackClientPsr6CacheDecorator 也将实现 IpstackClientInterface,因此可以透明地替换 IpstackClient

其构造函数接受您的 IpstackClient 实例和一个 PSR-6 CacheItemPool 实例。此示例使用来自 Stash 的缓存实现

<?php
use Germania\IpstackClient\IpstackClientPsr6CacheDecorator;
use Germania\IpstackClient\IpstackClient;
use Stash\Pool as CacheItemPool;

// Setup your client as shown above
$ipstack = new IpstackClient( $endpoint, $api_key);

// Example cache 
$cache   = new \Stash\Pool(
  new \Stash\Driver\Sqlite( array('path' => "/tmp" ))
);

// Setup the decorator
$caching_ipstack = new IpstackClientPsr6CacheDecorator($ipstack, $cache);

// Optional: Set lifetime in seconds (or null)
$caching_ipstack->setCacheLifeTime( 3600 );

// Use as usual
$response = $caching_ipstack->get( "8.8.8.8" );

中间件

IpstackMiddleware 可以用作 PSR-15 中间件以及传统的 Slim3-style “双遍历”中间件。它需要一个 IpstackClient 实例,并将携带 IpstackClient 的响应的 ipstack 属性注入到 Request 对象中。此示例显示了“双遍历”方法

<?php
use Germania\IpstackClient\IpstackMiddleware;

// Setup your client as shown above
$ipstack = new IpstackClient( $endpoint, $api_key);

// The middleware:
$ipstack_middleware = new IpstackMiddleware( $ipstack );

// Setup Slim app
$app = new \Slim\App;
$app->add( $ipstack_middleware );

然后在您的控制器中,您只需从 Request 对象中获取 ipsatck 信息即可

$ipstack_attr = $request->getAttribute( "ipstack" );

echo $ipstack_attr['ip'];
echo $ipstack_attr['country_code'];
echo $ipstack_attr['country_name'];

关于 IP 地址的说明

默认情况下,用于 ipstack 请求的 IP 地址由 $_SERVER['REMOTE_ADDR'] 确定。建议使用 Rob Allen(别称 akrabat)的 客户端 IP 地址中间件 来更安全地确定 IP 地址。

陷阱 1:Akrabats 中间件必须在 IpstackMiddleware 之前使用。它必须作为 Slim 应用程序中的第二个中间件添加。

陷阱 2:Akrabats 中间件允许自定义客户端 IP 地址的请求属性名称。根据文档

默认情况下,属性名称为 'ip_address'。可以通过第三个构造函数参数进行更改。

这意味着 IP 地址可能存储在自定义请求属性中。因此,IpstackMiddleware 必须知道此属性名称。

只需将 IP 地址属性名称作为第二个构造函数参数传递即可,无论是默认值还是自定义值。请记住,如果您省略此参数,则将使用 $_SERVER['REMOTE_ADDR'] 作为后备。

<?php
use RKA\Middleware\IpAddress as IpAddressMiddleware;
use Germania\IpstackClient\IpstackMiddleware;

// Setup Slim app
$app = new \Slim\App;

// Executed second
$ipstack_middleware = new IpstackMiddleware( $ipstack, "ip_address" );
$app->add( $ipstack_middleware );

// Executed first
$checkProxyHeaders = true; // Note: Never trust the IP address for security processes!
$trustedProxies = ['10.0.0.1', '10.0.0.2']; // example
$akrabats_middleware = new IpAddressMiddleware($checkProxyHeaders, $trustedProxies);
$app->add( $akrabats_middleware );

异常

IpstackClient 在请求期间检查 Guzzle 异常 并评估 ipstack 错误响应。两者都将被抽象为 IpstackRequestExceptionIpstackResponseException,分别实现 IpstackExceptionInterface

<?php
use Germania\IpstackClient\IpstackExceptionInterface;
use Germania\IpstackClient\IpstackRequestException;
use Germania\IpstackClient\IpstackResponseException;

try {
  $ipstack = new IpstackClient( $endpoint, $api_key);
  $response = $ipstack->get( $client_ip );
}
catch( IpstackExceptionInterface $e ) {

  // a) IpstackResponseException
  // b) IpstackRequestException 
  echo $e->getMessage();
  echo $e->getCode();  
  
  // to get Guzzle's original exception:
  $original_guzzle_exception = $e->getPrevious();
}

开发

$ git clone https://github.com/GermaniaKG/ipstack.git
$ cd ipstack
$ composer install

单元测试

phpunit.xml.dist 复制到 phunit.xml,并调整与 ipstack 相关的全局变量。端点和 API 密钥是自解释的;虚拟的 IP4IP6 是在测试运行期间需要检查的 IP 地址。这里使用的 IP 示例是 Google 的 DNS 服务器

<php>
  <var name="IPSTACK_ENDPOINT"   value="http://api.ipstack.com/" />
  <var name="IPSTACK_APIKEY"     value="your_api_key" />
  <var name="IPSTACK_DUMMY_IP4"  value="8.8.4.4" />
  <var name="IPSTACK_DUMMY_IP6"  value="2001:4860:4860::8888" />
</php>

使用供应商二进制文件或 composer 的 test 脚本运行 phpunit

$ vendor/bin/phpunit
# or
$ composer test