PHPでIPアドレスを判定してアクセスを制限する

IPアドレスを判断してアクセス制御するスクリプト。.htaccessのアクセス制限と比べると柔軟に対応できる。

1. 概要

PHPでIPアドレスを判定してアクセスを制限するためのスクリプト。

.htaccessのアクセス制限だとディレクトリ単位のアクセス許可/拒否しかできないが、PHPスクリプトで実装すれば細かい制御が出来る。(例:海外からのアクセスだとコメント投稿欄を非表示にする)

許可IP範囲は自分の好きに設定できるので「日本国外拒否」「会社単位」「自分だけ」とかもオッケーです。

2. スクリプト

/*
 * IPアドレスのチェック
 * @param   String  $remoteIp     リモートIP
 * @param   String  $allowIpFile  許可IPリストのファイル
 * @return  boolean
 */
function checkIp($remoteIp, $allowIpFile){
    if (!file_exists($allowIpFile)) die('file not found!! :'. $allowIpFile);
    foreach (@file($allowIpFile) as $ipAndMask){
        $ipAndMask = chop($ipAndMask);
        if (''  === $ipAndMask)               continue;
        if ('#' === substr($ipAndMask, 0, 1)) continue;

        list($allowIp, $mask) = explode("/", $ipAndMask);

        $remoteLong = ip2long($remoteIp) >> (32 - $mask);
        $allowLong  = ip2long($allowIp)  >> (32 - $mask);

        if ($remoteLong == $allowLong) return true;
    }
    return false;
}

3. 許可IPリストファイルの例

# 本社
192.168.1.0/24

# ○○営業所
192.168.2.0/24

# ××営業所
192.168.2.0/24

# リモート (Aさん)
111.111.111.111/32

# リモート (Bさん)
222.222.222.222/32
この例だとアクセス可能なIPアドレスは以下のようになります。

  • 192.168.1.0 〜 192.168.1.255
  • 192.168.2.0 〜 192.168.2.255
  • 111.111.111.111
  • 222.222.222.222

4. 使用例

// 許可IP範囲ファイル(allow_ip_list.txt)は同一ディレクトリにあると想定。
if (checkIp($_SERVER["REMOTE_ADDR"], 'allow_ip_list.txt')){
    echo "許可";
}else{
    echo "不許可";
}

5. おまけ(国内のみ許可のファイル生成)

国内のみアクセス許可するリストを生成するスクリプトです。 データはhttps://ftp.apnic.net/stats/apnic/delegated-apnic-latestから取得します。

<?php
$site	= 'https://ftp.apnic.net/stats/apnic/delegated-apnic-latest';

print "<pre>\n";
print '# '. date('Y/m/d H:i'). "\n";
print '# '. $site. "\n";
print "\n";

foreach (file($site) as $line){
    if ('apnic|JP|ipv4'	!== substr($line, 0, 13))	continue;

    list($dmy1, $dmy2, $dmy3, $ip, $scope, $dmy4, $status) = explode("|", $line);

    if ('allocated' != trim($status) && 'assigned' != trim($status)) continue;

    $prefix = log($scope) / log(2);
    $prefix = 32 - $prefix;

    print "{$ip}/$prefix\n";
}

print "</pre>\n";
実行結果
(ネットワークの速度によりますが、実行完了まで少々時間がかかります)

6. 注意事項

  • IPv6には対応していません。
  • アドレスは0埋めNGです。ip2long()関数がfalseを返します。(NG: “123.003.012.001” → OK: “123.3.12.1”)