LoginSignup
1
0

More than 1 year has passed since last update.

PHP IPアドレスが指定した範囲内にあるかどうか判別する関数を適当に書いた

Last updated at Posted at 2022-05-10

概要

googlebotなどのクローラーがアクセスしてきた時に、特定の処理を除外するために書いた。例えば広告を表示しないなど。

参考:IPアドレスが指定した範囲内にあるかどうか判別する

範囲の形式

  • 完全一致 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);
}
1
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0