概要
googlebotなどのクローラーがアクセスしてきた時に、特定の処理を除外するために書いた。例えば広告を表示しないなど。
範囲の形式
- 完全一致 192.168.0.1
- マスク 192.168.0.0/24
- マスク 192.168.0.100/24
- from/to 192.168.0.100/192.168.0.200
PHPUnitテスト
public function test_accept_ip() {
// 完全一致
$this->assertTrue(accept_ip('192.168.0.1', '192.168.0.1'));
$this->assertFalse(accept_ip('192.168.0.1', '192.168.0.22'));
// マスク
$this->assertTrue(accept_ip('192.168.0.1', '192.168.0.0/24'));
$this->assertFalse(accept_ip('192.168.0.1', '192.168.0.22/24'));
$this->assertTrue(accept_ip('192.168.0.23', '192.168.0.22/24'));
$this->assertTrue(accept_ip('66.249.71.129', '66.249.71.128/27'));
$this->assertFalse(accept_ip('66.249.71.127', '66.249.71.128/27'));
$this->assertFalse(accept_ip('66.249.64.191', '66.249.64.192/27'));
$this->assertTrue(accept_ip('66.249.64.192', '66.249.64.192/27'));
$this->assertTrue(accept_ip('66.249.64.223', '66.249.64.192/27'));
$this->assertFalse(accept_ip('66.249.64.224', '66.249.64.192/27'));
// from/to
$this->assertTrue(accept_ip('148.64.56.64', '148.64.56.64/148.64.56.80'));
$this->assertFalse(accept_ip('148.64.56.63', '148.64.56.64/148.64.56.80'));
$this->assertTrue(accept_ip('148.64.56.80', '148.64.56.64/148.64.56.80'));
$this->assertFalse(accept_ip('148.64.56.81', '148.64.56.64/148.64.56.80'));
// 引数が不正
set_error_handler(function(){});
$this->assertFalse(accept_ip('', null));
$this->assertFalse(accept_ip(null, null));
$this->assertFalse(accept_ip('ABCDEFG', null));
$this->assertFalse(accept_ip('148.64.56.81', ''));
$this->assertFalse(accept_ip('148.64.56.81', null));
$this->assertFalse(accept_ip('148.64.56.81', 'ABCDEFG'));
$this->assertFalse(accept_ip('148.64.56.81', 'ABCDEFG/24'));
$this->assertFalse(accept_ip('148.64.56.81', '148.64.56.64/ABCDEFG'));
$this->assertFalse(accept_ip('148.64.56.81', 'ABCDEFG/148.64.56.64'));
}
PHP
/**
* $remote_ipが$accept_ipの定義に当てはまるか
* @see 参考 https://qiita.com/ran/items/039706c93a8ff85a011a
*
* @param string $remote_ip
* @param string $accept_ip
* @return bool
*
*/
function accept_ip($remote_ip, $accept_ip) {
if (! valid_ip($remote_ip, 'ipv4')) {
trigger_error(__FUNCTION__.'(): Argument #1 ($remote_ip) must be in the form of an IP address.', E_USER_WARNING);
return false;
}
if (strpos($accept_ip, '/')) {
$tmp = explode('/', $accept_ip);
$accept_ip = $tmp[0];
$remote_long = ip2long($remote_ip);
// サブネットマスク のパターン
if (ctype_digit($tmp[1])) {
if (! valid_ip($accept_ip, 'ipv4')) {
trigger_error(__FUNCTION__.'(): Argument #2 ($accept_ip) must be in the form of an IP address.', E_USER_WARNING);
return false;
}
$mask = $tmp[1];
$accept_long = ip2long($accept_ip);
$remote_long_prefix = $remote_long >> (32 - $mask);
$accept_long_prefix = $accept_long >> (32 - $mask);
return ($remote_long_prefix === $accept_long_prefix && $remote_long >= $accept_long);
}
// 範囲下/範囲上 のパターン
else if (valid_ip($tmp[1], 'ipv4')) {
$accept_long_gte = ip2long($accept_ip);
$accept_long_lte = ip2long($tmp[1]);
return ($accept_long_gte <= $remote_long && $remote_long <= $accept_long_lte);
}
trigger_error(__FUNCTION__.'(): Argument #2 ($accept_ip) must be in the form of an IP address.', E_USER_WARNING);
return false;
}
if (! valid_ip($accept_ip, 'ipv4')) {
trigger_error(__FUNCTION__.'(): Argument #2 ($accept_ip) must be in the form of an IP address.', E_USER_WARNING);
return false;
}
if ($accept_ip === $remote_ip) {
return true;
}
return false;
}
/**
* Validate IP Address
*
* @param string $ip
* @param string $options 'ipv4' or 'ipv6' to validate a specific IP format
* @return bool
*/
function valid_ip($ip, $options = null) {
if (! is_null($options)) {
$which = strtolower($options);
if ('ipv4' === $which) {
$options = 1048576;
}
else if ('ipv6' === $which) {
$options = 2097152;
}
}
return (bool)filter_var($ip, 275, $options);
}