germania-kg/ipstack

支持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风格的“双重传递”中间件。它需要IpstackClient实例,并将一个携带IpstackClient's响应的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 复制到 phpunit.xml 并调整与ipstack相关的全局变量。端点和API密钥解释自明;虚拟的 IP4IP6 是测试运行期间要检查的IP地址。这里使用的IP示例是 谷歌的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