Chuck Le Butt
Chuck Le Butt

Reputation: 48818

Storing and retrieving IPv4 and IPv6 addresses

There's a million questions on SO about the best way to store IPv4 and IPv6 addresses on a PHP/MySQL setup, but the answers are either out of date (only IPv4) or they're contradictory/incomplete.

I've created this question to go with a clear answer that gives you everything you need to know.

Upvotes: 1

Views: 2816

Answers (2)

Chuck Le Butt
Chuck Le Butt

Reputation: 48818

When you only had to worry about IPv4, you could use PHP's ip2long and long2ip to quickly and easily convert an IP address to a integer. These days, however, nearly everyone should expect to come across some IPv6 addresses at some point, and that's something that's only going to increase.

A common and efficient solution to have both is to use PHP's inet_pton function (which handles both IPv4 and v6), and then store the result in a VARBINARY(16) column in your database.

So, let's say we have an IPv6 address like: FE80:0000:0000:0000:0202:B3FF:FE1E:8329

When converted with inet_pton and stored in a VARBINARY(16) column it looks like this:

0xfe800000000000000202b3fffe1e8329

You can then retrieve this from your database and display it using inet_ntop.

Eg:

echo inet_ntop($ipAddressFromDB);

This is a quick and efficient way to store IP addresses in an MySQL database.

Upvotes: 3

Sammitch
Sammitch

Reputation: 32272

At this point in time you're doing yourself a disservice if you're not building your application to accommodate IPv6, and this is going to become even more true over time. For this reason I've started storing all IP addresses in IPv6 format, and using 6to4 notation for IPv4 addresses.

The TL;DR for 6to4 is:

The first 16 bits of the prefix are always 2002:, the next 32 bits are the IPv4 address, and the last 16 bits of the prefix are [not important for this purpose]

So let's say that your IP address is 222.173.190.239, we convert that to 6to4 notation by:

sprintf('2002:%s::', implode(':', str_split(str_pad(dechex(ip2long($addr)), 8, '0', STR_PAD_LEFT), 2)));

Which becomes: 2002:de:ad:be:ef::

Which you convert to binary form for storage by: inet_pton('2002:de:ad:be:ef::');

Which gives the 16-byte binary: 0x200200de00ad00be00ef000000000000

Which should be easily store-able and searchable.

I've previously written a helper class for this, and I've just pushed it up to Github and Packagist in case someone else might find it useful.

Upvotes: 0

Related Questions