Вход Регистрация
Файл: library/XenForo/Helper/Ip.php
Строк: 374
<?php

class XenForo_Helper_Ip
{
    
/**
     * Gets the binary form of the provided IP or if no IP is provided, from the request.
     * Binary IPs are IPv4 or IPv6 IPs compressed into 4 or 16 bytes.
     *
     * @param Zend_Controller_Request_Http|null $request Request object used; created if needed
     * @param string|null $ip String value of the IP to use or null to read from request
     * @param mixed $invalidValue Value to use for the IP if no valid IP is available
     *
     * @return mixed Usually a string containing a binary IP, but can be the invalid value
     */
    
public static function getBinaryIp(Zend_Controller_Request_Http $request null$ip null$invalidValue false)
    {
        if (!
$ip)
        {
            if (
$request)
            {
                
$ip $request->getServer('REMOTE_ADDR');
            }
            else
            {
                
$ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null;
            }
        }

        
$ip $ip self::convertIpStringToBinary($ip) : false;
        return 
$ip !== false $ip $invalidValue;
    }

    
/**
     * Converts a string based IP (v4 or v6) to a 4 or 16 byte string.
     * This tries to identify not only 192.168.1.1 and 2001::1:2:3:4 style IPs,
     * but integer encoded IPv4 and already binary encoded IPs. IPv4
     * embedded in IPv6 via things like ::ffff:192.168.1.1 is also detected.
     *
     * @param string|int $ip
     *
     * @return bool|string False on failure, binary data otherwise
     */
    
public static function convertIpStringToBinary($ip)
    {
        
$originalIp $ip;
        
$ip trim($ip);

        if (
strpos($ip':') !== false)
        {
            
// IPv6
            
if (preg_match('#:(d{1,3}.d{1,3}.d{1,3}.d{1,3})$#'$ip$match))
            {
                
// embedded IPv4
                
$long ip2long($match[1]);
                if (!
$long)
                {
                    return 
false;
                }

                
$hex str_pad(dechex($long), 8'0'STR_PAD_LEFT);
                
$v4chunks str_split($hex4);
                
$ip str_replace($match[0], ":$v4chunks[0]:$v4chunks[1]"$ip);
            }

            if (
strpos($ip'::') !== false)
            {
                if (
substr_count($ip'::') > 1)
                {
                    
// ambiguous
                    
return false;
                }

                
$delims substr_count($ip':');
                if (
$delims 7)
                {
                    return 
false;
                }

                
$ip str_replace('::'str_repeat(':0'$delims) . ':'$ip);
                if (
$ip[0] == ':')
                {
                    
$ip '0' $ip;
                }
            }

            
$ip strtolower($ip);

            
$parts explode(':'$ip);
            if (
count($parts) != 8)
            {
                return 
false;
            }

            foreach (
$parts AS &$part)
            {
                
$len strlen($part);
                if (
$len || preg_match('/[^0-9a-f]/'$part))
                {
                    return 
false;
                }

                if (
$len 4)
                {
                    
$part str_repeat('0'$len) . $part;
                }
            }

            
$hex implode(''$parts);
            if (
strlen($hex) != 32)
            {
                return 
false;
            }

            return 
XenForo_Helper_Ip::convertHexToBin($hex);
        }
        else if (
strpos($ip'.'))
        {
            
// IPv4
            
if (!preg_match('#(d{1,3}.d{1,3}.d{1,3}.d{1,3})#'$ip$match))
            {
                return 
false;
            }

            
$long ip2long($match[1]);
            if (!
$long)
            {
                return 
false;
            }

            return 
XenForo_Helper_Ip::convertHexToBin(
                
str_pad(dechex($long), 8'0'STR_PAD_LEFT)
            );
        }
        else if (
strlen($ip) == || strlen($ip) == 16)
        {
            
// already binary encoded
            
return $ip;
        }
        else if (
is_numeric($originalIp) && $originalIp pow(232))
        {
            
// IPv4 as integer
            
return XenForo_Helper_Ip::convertHexToBin(
                
str_pad(dechex($originalIp), 8'0'STR_PAD_LEFT)
            );
        }
        else
        {
            return 
false;
        }
    }

    
/**
     * Converts a hex string to binary
     *
     * @param string $hex
     *
     * @return string
     */
    
public static function convertHexToBin($hex)
    {
        if (
function_exists('hex2bin'))
        {
            return 
hex2bin($hex);
        }

        
$len strlen($hex);

        if (
$len 2)
        {
            
trigger_error('Hexadecimal input string must have an even length'E_USER_WARNING);
        }

        if (
strspn($hex'0123456789abcdefABCDEF') != $len)
        {
            
trigger_error('Input string must be hexadecimal string'E_USER_WARNING);
        }

        return 
pack('H*'$hex);
    }

    
/**
     * Converts a binary string containing IPv4 or v6 data to a printable/human
     * readable version. If shortening is enabled, IPv6 data will be collapsed
     * as much as possible.
     *
     * @param string $ip Binary IP data
     * @param bool $shorten
     *
     * @return bool|string
     */
    
public static function convertIpBinaryToString($ip$shorten true)
    {
        if (
strlen($ip) == 4)
        {
            
// IPv4
            
$parts = array();
            foreach (
str_split($ip) AS $char)
            {
                
$parts[] = ord($char);
            }

            return 
implode('.'$parts);
        }
        else if (
strlen($ip) == 16)
        {
            
// IPv6
            
$parts = array();
            
$chunks str_split($ip);
            for (
$i 0$i 16$i += 2)
            {
                
$char1 $chunks[$i];
                
$char2 $chunks[$i 1];

                
$part sprintf('%02x%02x'ord($char1), ord($char2));
                if (
$shorten)
                {
                    
// reduce this to the shortest length possible, but keep 1 zero if needed
                    
$part ltrim($part'0');
                    if (!
strlen($part))
                    {
                        
$part '0';
                    }
                }
                
$parts[] = $part;
            }

            
$output implode(':'$parts);
            if (
$shorten)
            {
                
$output preg_replace('/((^0|:0){2,})(.*)$/'':$3'$output);
            }

            return 
strtolower($output);
        }
        else if (
preg_match('/^[0-9]+$/'$ip))
        {
            return 
long2ip($ip 0);
        }
        else
        {
            return 
false;
        }
    }

    
/**
     * Gets the range of binary-encoded IPs that match the given
     * CIDR block size. Supports IPv4 and v6. Ranges can be checked
     * via >= lower and <= upper.
     *
     * @param string $ip Binary IP
     * @param integer $cidr CIDR range
     *
     * @return array|string If no CIDR is specified or if the CIDR specifies only one address, a string with that address.
     *         Otherwise, an array with a lower and upper bound.
     */
    
public static function getIpCidrMatchRange($ip$cidr)
    {
        if (!
$cidr)
        {
            return 
$ip;
        }

        
$bytes strlen($ip);
        
$bits $bytes 8;
        if (
$cidr >= $bits)
        {
            return 
$ip// exact match
        
}

        
$prefixBytes = (int)floor($cidr 8);
        
$remainingBits = ($cidr $prefixBytes 8);

        
$prefix substr($ip0$prefixBytes);
        if (
$remainingBits)
        {
            
$partialByteOrd ord($ip[$prefixBytes]); // first character after full prefix bytes
            
$mask = (<< $remainingBits) - 1;

            
$upperBound chr($partialByteOrd $mask);
            
$lowerBound chr($partialByteOrd & ~$mask);
            
$boundLength 1;
        }
        else
        {
            
$upperBound '';
            
$lowerBound '';
            
$boundLength 0;
        }

        
$suffixBytes $bytes $prefixBytes $boundLength;
        if (
$suffixBytes)
        {
            
$lowerSuffix str_repeat(chr(0), $suffixBytes);
            
$upperSuffix str_repeat(chr(255), $suffixBytes);
        }
        else
        {
            
$lowerSuffix '';
            
$upperSuffix '';
        }

        return array(
$prefix $lowerBound $lowerSuffix$prefix $upperBound $upperSuffix);
    }

    
/**
     * Determines if a particular IP matches a IP CIDR range.
     * Both IPs must be binary encoded
     *
     * @param string $testIp Binary encoded IP to test if within range
     * @param string $rangeIp Binary encoded IP to make the range from
     * @param integer $cidr CIDR block size
     *
     * @return bool
     */
    
public static function ipMatchesCidrRange($testIp$rangeIp$cidr)
    {
        
$range self::getIpCidrMatchRange($rangeIp$cidr);
        if (
is_string($range))
        {
            return (
$testIp == $range);
        }
        else
        {
            return 
self::ipMatchesRange($testIp$range[0], $range[1]);
        }
    }

    
/**
     * Simplifies checking if an IP is within a range.
     * All IPs and ranges must be binary encoded.
     *
     * @param string $testIp
     * @param string $lowerBound
     * @param string $upperBound
     *
     * @return bool
     */
    
public static function ipMatchesRange($testIp$lowerBound$upperBound)
    {
        return (
$testIp >= $lowerBound AND $testIp <= $upperBound AND strlen($testIp) == strlen($lowerBound));
    }

    
/**
     * Parses a human readable IP range string into a machine processable version.
     * IPv4 can be specified with CIDR or 192.168.* style ranges. IPv6 supports CIDR only.
     *
     * @param string $ip Human readable IPv4 or v6 IP
     *
     * @return array|bool False on failure, Otherwise array with following keys:
     *         - printable: human readable version of the IP range. May be adjusted to standardize display slightly
     *         - binary: binary version of provided IP. IPv4 missing octets are considered to be 0.
     *         - cidr: the final CIDR range found/used. If a IPv4 partial is provided, this will be determined from number of missing octets. 0 for exact.
     *         - isRange: true if the provided IP actually spans a range
     *        - startRange: binary version of lower bound IP
     *        - endRange: binary version of upper bound IP
     */
    
public static function parseIpRangeString($ip)
    {
        
$ip trim($ip);
        
$niceIp $ip;

        if (
preg_match('#/(d+)$#'$ip$match))
        {
            
$ip substr($ip0, -strlen($match[0]));
            
$cidr $match[1];
            if (
$cidr && $cidr 8)
            {
                
$cidr 8;
                
$niceIp $ip "/$cidr";
            }
        }
        else
        {
            
$cidr 0;
        }

        if (
strpos($ip':') !== false)
        {
            
// IPv6 -- no partials, only CIDR
            
$binary self::convertIpStringToBinary($ip);
            if (
$binary === false)
            {
                return 
false;
            }
        }
        else
        {
            
$ip preg_replace('/.+$/'''$ip);
            if (!
preg_match('/^d+(.d+){0,2}(.d+|.*)?$/'$ip))
            {
                return 
false;
            }

            if (
substr($ip, -2) == '.*')
            {
                
$ip substr($ip0, -2);
            }

            
$ipParts explode('.'$ip);
            foreach (
$ipParts AS $part)
            {
                if (
$part || $part 255)
                {
                    return 
false;
                }
            }

            
$localCidr 32;
            while (
count($ipParts) < 4)
            {
                
$ipParts[] = 0;
                
$localCidr -= 8;
            }

            if (!
$cidr && $localCidr != 32)
            {
                
$cidr $localCidr;
                
$niceIp $ip '.*';
            }

            
$binary self::convertIpStringToBinary(implode('.'$ipParts));
            if (!
$binary)
            {
                return 
false;
            }
        }

        
$range self::getIpCidrMatchRange($binary$cidr);

        return array(
            
'printable' => $niceIp,
            
'binary' => $binary,
            
'cidr' => $cidr,
            
'isRange' => is_array($range),
            
'startRange' => is_string($range) ? $range $range[0],
            
'endRange' => is_string($range) ? $range $range[1]
        );
    }
}
Онлайн: 3
Реклама