IP::Country::Fast の PHP 版

IP::Country::Fast の PHP 版 #

ip address から国を知りたい時、Perl だと IP::Country::Fast とか使うんだが、PHP だと何を使うんだろう。。。と探したけどなかったので、PHP 版でっちあげた

Perl 版の ip.gif と cc.gif をそのまま使うし、Perl で書いてるのを PHP で書きなおしただけ。まさにでっちあげ

require_once 'IP_Country_Fast.php';

$ip = new IP_Country_Fast('/path/to/pellib/IP/Country/Fast/');
echo $ip->inet_atocc('124.83.203.233');

// result: JP

以下、ソースコード。そのうちテストケースつけて github にあげます

<?php
class IP_Country_Fast {
    function __construct($dbpath = './') {
        date_default_timezone_set('Asia/Tokyo');
        $this->bit0 = substr(pack('N', pow(2,31)),0,1);
        $this->bit1 = substr(pack('N', pow(2,30)),0,1);
        $this->mask = array();
        $this->dtoc = array();
        $this->cc = array();

        for ( $i = 0; $i < 32; $i++ )
            array_push( $this->mask, pack('N', pow(2, 31 - $i)) );
        for ( $i = 0; $i < 256; $i++ )
            array_push( $this->dtoc, substr( pack('N', $i), 3, 1) );

        // cc.gif
        if ( ! $cc_ultra = file_get_contents($dbpath . 'cc.gif') )
            exit();
        $cc_num = strlen($cc_ultra) / 3;
        for ( $i = 0; $i < $cc_num; $i++ ) {
            $ccchar = substr($cc_ultra, 3 * $i + 1, 2);
            if ( $ccchar === '--' ) { $ccchar = null; }
            $this->cc[ substr( $cc_ultra, 3 * $i, 1 ) ] = $ccchar;
        }

        // ip.gif
        if ( ! $this->ip_db = file_get_contents($dbpath . 'ip.gif') )
            exit();
    }

    public function inet_atocc($inet_a) {
        $ip_regex = '/^(\d|[01]?\d\d|2[0-4]\d|25[0-5])\.(\d|[01]?\d\d|2[0-4]\d|25[0-5])\.(\d|[01]?\d\d|2[0-4]\d|25[0-5])\.(\d|[01]?\d\d|2[0-4]\d|25[0-5])$/';
        if ( preg_match($ip_regex, $inet_a, $matches) ) {
            return $this->inet_ntocc($this->dtoc[$matches[1]].$this->dtoc[$matches[2]].$this->dtoc[$matches[3]].$this->dtoc[$matches[4]]);
        }
        else {
            return null;
        }
    }

    public function inet_ntocc($inet_n) {
        $pos = 4;
        $null = substr(pack('N',0), 0, 1);
        $nullnullnull = $null . $null . $null;

        $byte_zero = substr($this->ip_db, $pos, 1);

        for ($i=0; $i<=31; $i++) {
            if( ($inet_n & $this->mask[$i]) === $this->mask[$i] ) {
                if ( ($byte_zero & $this->bit1) === $this->bit1 ) {
                    $unpacked = unpack('N', $nullnullnull . ($byte_zero ^ $this->bit1) );
                    $pos = $pos + 1 + $unpacked[1];
                }
                else {
                    $unpacked = unpack('N', $null . substr($this->ip_db, $pos, 3));
                    $pos = $pos + 3 + $unpacked[1];
                }
            }
            else {
                if ( ($byte_zero & $this->bit1) === $this->bit1 ) {
                    $pos = $pos + 1;
                }
                else {
                    $pos = $pos + 3;
                }
            }
            $byte_zero = substr($this->ip_db,$pos,1);
            if( ($byte_zero & $this->bit0) === $this->bit0 ) {
                if ( ($byte_zero & $this->bit1) === $this->bit1) {
                    return $this->cc[ substr($this->ip_db, $pos + 1, 1) ];
                }
                else {
                    return $this->cc[$byte_zero ^ $this->bit0];
                }
            }
        }
    }
}

See Also

Copyright © 髭。/ Hugo + hugo-book