在仔细搜索之后,我注意到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 /sf/ask/17360801/ */ 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()
?然后,您只需使用a varbinary(16)
来存储它,而不是将事物整理成整数.