문제

다소 철저한 검색 후, 나는 처리를 위해 PHP의 기능이 약간 부족하다는 것을 알았습니다. IPv6. 내 자신의 개인적인 만족을 위해 나는 전환을 돕기 위해 몇 가지 기능을 만들었습니다.

그만큼 IPv6ToLong() 기능은 여기에 제기 된 일시적인 솔루션입니다. 관계형 데이터베이스에 IPv6 호환 주소를 저장하는 방법. IP를 두 정수로 분할하여 배열로 반환합니다.

/**
 * Convert an IPv4 address to IPv6
 *
 * @param string IP Address in dot notation (192.168.1.100)
 * @return string IPv6 formatted address or false if invalid input
 */
function IPv4To6($Ip) {
    static $Mask = '::ffff:'; // This tells IPv6 it has an IPv4 address
    $IPv6 = (strpos($Ip, '::') === 0);
    $IPv4 = (strpos($Ip, '.') > 0);

    if (!$IPv4 && !$IPv6) return false;
    if ($IPv6 && $IPv4) $Ip = substr($Ip, strrpos($Ip, ':')+1); // Strip IPv4 Compatibility notation
    elseif (!$IPv4) return $Ip; // Seems to be IPv6 already?
    $Ip = array_pad(explode('.', $Ip), 4, 0);
    if (count($Ip) > 4) return false;
    for ($i = 0; $i < 4; $i++) if ($Ip[$i] > 255) return false;

    $Part7 = base_convert(($Ip[0] * 256) + $Ip[1], 10, 16);
    $Part8 = base_convert(($Ip[2] * 256) + $Ip[3], 10, 16);
    return $Mask.$Part7.':'.$Part8;
}

/**
 * Replace '::' with appropriate number of ':0'
 */
function ExpandIPv6Notation($Ip) {
    if (strpos($Ip, '::') !== false)
        $Ip = str_replace('::', str_repeat(':0', 8 - substr_count($Ip, ':')).':', $Ip);
    if (strpos($Ip, ':') === 0) $Ip = '0'.$Ip;
    return $Ip;
}

/**
 * Convert IPv6 address to an integer
 *
 * Optionally split in to two parts.
 *
 * @see https://stackoverflow.com/questions/420680/
 */
function IPv6ToLong($Ip, $DatabaseParts= 2) {
    $Ip = ExpandIPv6Notation($Ip);
    $Parts = explode(':', $Ip);
    $Ip = array('', '');
    for ($i = 0; $i < 4; $i++) $Ip[0] .= str_pad(base_convert($Parts[$i], 16, 2), 16, 0, STR_PAD_LEFT);
    for ($i = 4; $i < 8; $i++) $Ip[1] .= str_pad(base_convert($Parts[$i], 16, 2), 16, 0, STR_PAD_LEFT);

    if ($DatabaseParts == 2)
            return array(base_convert($Ip[0], 2, 10), base_convert($Ip[1], 2, 10));
    else    return base_convert($Ip[0], 2, 10) + base_convert($Ip[1], 2, 10);
}

이 기능의 경우 일반적 으로이 기능을 먼저 호출하여 구현합니다.

/**
 * Attempt to find the client's IP Address
 *
 * @param bool Should the IP be converted using ip2long?
 * @return string|long The IP Address
 */
function GetRealRemoteIp($ForDatabase= false, $DatabaseParts= 2) {
    $Ip = '0.0.0.0';
    if (isset($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] != '')
        $Ip = $_SERVER['HTTP_CLIENT_IP'];
    elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] != '')
        $Ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] != '')
        $Ip = $_SERVER['REMOTE_ADDR'];
    if (($CommaPos = strpos($Ip, ',')) > 0)
        $Ip = substr($Ip, 0, ($CommaPos - 1));

    $Ip = IPv4To6($Ip);
    return ($ForDatabase ? IPv6ToLong($Ip, $DatabaseParts) : $Ip);
}

누군가 내가 여기 바퀴를 재창조하는지 말해 주거나 뭔가 잘못했는지 말해줘.

이 구현은 IPv4를 IPv6으로 변환합니다. IPv6 주소는 터치하지 않습니다.

도움이 되었습니까?

해결책

어때 inet_ntop()? 그런 다음 물건을 정수로 자르는 대신 varbinary(16) 그것을 보관하려면.

다른 팁

php.net 's 필터 확장 포함 일부 상수 IPv4 및 IPv6 주소와 일치하는 경우 주소를 확인하는 데 유용 할 수 있습니다. 그래도 전환 유틸리티를 보지 못했습니다.

주소를 MySQL의 바이너리 (16)에 저장할 수도 있으므로 ipv6tolong ()에서 바이너리로 출력 할 수있는 옵션이 있어야합니다.

이것은 특히 많은 IPv6에서 웹사베르 보고서 :: FFFF : 1.2.3.4가 클라이언트 IP로서 IP2LONG과 호환되지 않으며 많은 것들을 깨뜨릴 때 PHP에 기본적으로 추가해야 할 것입니다.

다음은 filter_var (php> = 5.2)를 사용한 대체 기능입니다.

function IPv4To6($ip) {
 if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === true) {
  if (strpos($ip, '.') > 0) {
   $ip = substr($ip, strrpos($ip, ':')+1);
  } else { //native ipv6
   return $ip;
  }
 }
 $is_v4 = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
 if (!$is_v4) { return false; }
 $iparr = array_pad(explode('.', $ip), 4, 0);
    $Part7 = base_convert(($iparr[0] * 256) + $iparr[1], 10, 16);
    $Part8 = base_convert(($iparr[2] * 256) + $iparr[3], 10, 16);
    return '::ffff:'.$Part7.':'.$Part8;
}

돌아가서, 나는 두 가지 기능을 썼습니다. dtr_pton 그리고 dtr_ntop IPv4 및 IPv6과 함께 작동합니다. 인쇄용과 이진 사이에서 앞뒤로 변환합니다.

첫 번째 함수, dtr_pton 제공된 인수가 유효한 IPv4 또는 유효한 IPv6인지 확인합니다. 결과에 따라 예외가 발생하거나 IP의 이진 표현이 반환 될 수 있습니다. 이 기능을 사용하면 결과 (서브넷/whathaveyou의 경우)를 수행하고 또는 또는 또는 또는 '수행 할 수 있습니다. 데이터베이스에 이것을 저장하는 것이 좋습니다. VARBINARY(39) 또는 VARCHAR(39).

/**
* dtr_pton
*
* Converts a printable IP into an unpacked binary string
*
* @author Mike Mackintosh - mike@bakeryphp.com
* @param string $ip
* @return string $bin
*/
function dtr_pton( $ip ){

    if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)){
        return current( unpack( "A4", inet_pton( $ip ) ) );
    }
    elseif(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)){
        return current( unpack( "A16", inet_pton( $ip ) ) );
    }

    throw new \Exception("Please supply a valid IPv4 or IPv6 address");

    return false;
}

두 번째 함수, dtr_ntop IP의 이진 표현을 다시 인쇄 가능한 IP 주소로 변환합니다.

/**
* dtr_ntop
*
* Converts an unpacked binary string into a printable IP
*
* @author Mike Mackintosh - mike@bakeryphp.com
* @param string $str
* @return string $ip
*/
function dtr_ntop( $str ){
    if( strlen( $str ) == 16 OR strlen( $str ) == 4 ){
        return inet_ntop( pack( "A".strlen( $str ) , $str ) );
    }

    throw new \Exception( "Please provide a 4 or 16 byte string" );

    return false;
}

또한 IPv6 주소를 빠르게 확장하는 방법이 있습니다. stackoverflow에서 발견됩니다

function expand($ip){
    $hex = unpack("H*hex", inet_pton($ip));         
    $ip = substr(preg_replace("/([A-f0-9]{4})/", "$1:", $hex['hex']), 0, -1);

    return $ip;
}

또한 내 블로그에서 주제를 잘 읽을 수 있습니다. Highonphp : PHP에서 IPv6 작업을위한 5 가지 팁. 이 기사는 위에서 설명한 몇 가지 방법을 사용하여 객체 지향 클래스에서 찾을 수 있습니다. github : mikemackintosh dtr-ip

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top