<?php

namespace Hura8\System;

// copy from: https://php.net/manual/en/function.ip2long.php
//useage:
/*$filter = new IPFilter(
    array(
        '127.0.0.1',
        '172.0.0.*',
        '173.0.*.*',
        '126.1.0.0/255.255.0.0',
        '125.0.0.1-125.0.0.9',
    ));
$filter -> check('126.1.0.2');*/

class IPFilter
{
    private static $_IP_TYPE_SINGLE = 'single';
    private static $_IP_TYPE_WILDCARD = 'wildcard';
    private static $_IP_TYPE_MASK = 'mask';
    private static $_IP_TYPE_SECTION = 'section';
    private $_allowed_ips = array();

    public function __construct($allowed_ips)
    {
        $this -> _allowed_ips = $allowed_ips;
    }


    public function check($ip, $allowed_ips = null)
    {
        $allowed_ips = $allowed_ips ? $allowed_ips : $this->_allowed_ips;

        foreach($allowed_ips as $allowed_ip)
        {
            $type = $this->_judge_ip_type($allowed_ip);
            $sub_rst = call_user_func(array($this,'_sub_checker_' . $type), $allowed_ip, $ip);

            if ($sub_rst)
            {
                return true;
            }
        }

        return false;
    }


    private function _judge_ip_type($ip)
    {
        if (strpos($ip, '*'))
        {
            return self::$_IP_TYPE_WILDCARD;
        }

        if (strpos($ip, '/'))
        {
            return self::$_IP_TYPE_MASK;
        }

        if (strpos($ip, '-'))
        {
            return self::$_IP_TYPE_SECTION;
        }

        return self::$_IP_TYPE_SINGLE;

        /*if (ip2long($ip))
        {
            return self::$_IP_TYPE_SINGLE;
        }

        return false;*/
    }

    // can use for IPV4&6
    private function _sub_checker_single($allowed_ip, $ip)
    {
        return strval($allowed_ip) == strval($ip);
        //return (ip2long($allowed_ip) == ip2long($ip));
    }

    // currently only IPV4: 172.0.0.*
    private function _sub_checker_wildcard($allowed_ip, $ip)
    {
        $allowed_ip_arr = explode('.', $allowed_ip);
        $ip_arr = explode('.', $ip);
        for($i = 0;$i < count($allowed_ip_arr);$i++)
        {
            if ($allowed_ip_arr[$i] == '*')
            {
                return true;
            }
            else
            {
                if (false == ($allowed_ip_arr[$i] == $ip_arr[$i]))
                {
                    return false;
                }
            }
        }

        return true;
    }

    // currently only IPV4:  125.0.0.1/24
    private function _sub_checker_mask($banned_range, $ip)
    {
        // $allowed_ip is in IP/CIDR format eg 127.0.0.1/24
        list( $range, $netmask ) = explode( '/', $banned_range, 2 );
        $range_decimal = ip2long( $range );
        $ip_decimal = ip2long( $ip );
        $wildcard_decimal = pow( 2, ( 32 - $netmask ) ) - 1;
        $netmask_decimal = ~ $wildcard_decimal;
        return !( ( $ip_decimal & $netmask_decimal ) == ( $range_decimal & $netmask_decimal ) );
    }

    // currently only IPV4:  125.0.0.1-125.0.0.9
    private function _sub_checker_section($allowed_ip, $ip)
    {
        list($begin, $end) = explode('-', $allowed_ip);
        $begin  = ip2long(trim($begin));
        $end    = ip2long(trim($end));
        $ip     = ip2long($ip);

        return ($ip >= $begin && $ip <= $end);
    }
}
