Under IPv4
I have been parsing the string representation of IP addresses to Int32
and storing them as INT
in the SQL Server
I use the following method for converting an IP address to two UInt64
s (C# 3.0).
/// <summary>
/// Converts an IP address to its UInt64[2] equivalent.
/// For an IPv4 address, the first element will be 0,
/// and the second will be a UInt32 representation of the four bytes.
/// For an IPv6 address, the first element will be a UInt64
/// representation of the first eight bytes, and the second will be the
/// last eight bytes.
/// </summary>
/// <param name="ipAddress">The IP address to convert.</param>
/// <returns></returns>
private static ulong[] ConvertIPAddressToUInt64Array(string ipAddress)
{
byte[] addrBytes = System.Net.IPAddress.Parse(ipAddress).GetAddressBytes();
if (System.BitConverter.IsLittleEndian)
{
//little-endian machines store multi-byte integers with the
//least significant byte first. this is a problem, as integer
//values are sent over the network in big-endian mode. reversing
//the order of the bytes is a quick way to get the BitConverter
//methods to convert the byte arrays in big-endian mode.
System.Collections.Generic.List<byte> byteList = new System.Collections.Generic.List<byte>(addrBytes);
byteList.Reverse();
addrBytes = byteList.ToArray();
}
ulong[] addrWords = new ulong[2];
if (addrBytes.Length > 8)
{
addrWords[0] = System.BitConverter.ToUInt64(addrBytes, 8);
addrWords[1] = System.BitConverter.ToUInt64(addrBytes, 0);
}
else
{
addrWords[0] = 0;
addrWords[1] = System.BitConverter.ToUInt32(addrBytes, 0);
}
return addrWords;
}
Make sure you cast your UInt64
s to Int64
s before you put them into the database, or you'll get an ArgumentException
. When you get your values back out, you can cast them back to UInt64
to get the unsigned value.
I don't have a need to do the reverse (i.e. convert a UInt64[2]
to an IP string) so I never built a method for it.
If you are using SQL Server 2005, you can use the uniqueidentifier
type. This type stores 16 bytes, which is perfect for an IPv6 ip address. You can convert between IPAddress
and Guid
by using the constructors and ToByteArray
.
The simplest route is to get the framework to do this for you. Use IPAddress.Parse to parse the address, then IPAddress.GetAddressBytes to get the "number" as byte[].
Finally, divide the array into the first and second 8 bytes for conversion to two Int64s, e.g. by creating a MemoryStream
over the byte array and then reading via a BinaryReader
.
This avoids needing to understand all the available short cut representations for IPv6 addresses.
function encode_ip ($ip)
{
return bin2hex(inet_pton($ip));
}
function decode_ip($ip)
{
function hex2bin($temp) {
$data="";
for ($i=0; $i < strlen($temp); $i+=2) $data.=chr(hexdec(substr($temp,$i,2)));
return $data;
}
return inet_ntop(hex2bin($ip));
}
-- max len row db
echo strlen(inet_pton('2001:db8:85a3::8a2e:370:7334'));
-- db row info
ip varchar(16)
-- sql binary save and read
save base
$bin_ip='0x'.bin2hex(inet_pton($data['ip_address']));
-- db read
select ip_address from users;
-- encode binary from db
echo inet_ntop($row['ip_address']);
Just as an IPv4 address is really a 32 bit number, an IPv6 address is really a 128 bit number. There are different string representations of the addresses, but the actual address is the number, not the string.
So, you don't convert an IP address to a number, you parse a string representation of the address into the actual address.
Not even a decimal
can hold a 128 bit number, so that leaves three obvious alternatives:
bigint
fieldsvarchar
fieldbinary
fieldNeither is as convenient as storing an IPv4 address in an int
, so you have to consider their limitations against what you need to do with the addresses.