Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting an IPv6 address in PHP and storing it properly in MySQL. How?

Tags:

php

ipv6

I read a few of the questions already asked, and i found this to be useful, although i have no tried it Working with IPv6 Addresses in PHP

Still, say i have a 'bans' table in MySQL. How would i go about storing the IPv6 address? The method must be universal, i.e the field must be able to contain either a ipv4 or ipv6 addr. This also must apply to my ip_addr field in my users table.

i would usually check if(getip == $bans['ip']) { do something } But my getip function is for ipv4 afaik and i wonder if it will work.

The function i use is

function getip()
{
    if(isset($_SERVER['REMOTE_ADDR']))
    {
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    elseif(isset($_SERVER['HTTP_X_FORWARDED_FOR']))
    {
    if(preg_match_all("#[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}#s", $_SERVER['HTTP_X_FORWARDED_FOR'], $addresses))
    {
        foreach($addresses[0] as $key => $val)
        {
            if(!preg_match("#^(10|172\.16|192\.168)\.#", $val))
            {
                $ip = $val;
                break;
            }
        }
    }
}

if(!isset($ip))
{
    if(isset($_SERVER['HTTP_CLIENT_IP']))
    {
        $ip = $_SERVER['HTTP_CLIENT_IP'];
    }
    else
    {
        $ip = '';
    }
}

$ip = preg_replace("#([^.0-9 ]*)#", "", $ip);
return $ip;
}
like image 720
dikidera Avatar asked Jan 19 '23 14:01

dikidera


1 Answers

I was searching for the best data type in mysql to use for storing an ipv6 address recently. I have found no good reason to use a VARCHAR(), only good reasons NOT to.

I did some performance testing with the BINARY(16), two BIGINT UNSIGNED, and DECIMAL data types.

I've created the following tables, populated with 2,000,000 random ip address from 100 random networks.

CREATE TABLE ipv6_address_binary (
    id SERIAL NOT NULL AUTO_INCREMENT PRIMARY KEY,
    addr BINARY(16) NOT NULL UNIQUE
);

CREATE TABLE ipv6_address_twobigints (
    id SERIAL NOT NULL AUTO_INCREMENT PRIMARY KEY,
    haddr BIGINT UNSIGNED NOT NULL,
    laddr BIGINT UNSIGNED NOT NULL,
    UNIQUE uidx (haddr, laddr)
);

CREATE TABLE ipv6_address_decimal (
    id SERIAL NOT NULL AUTO_INCREMENT PRIMARY KEY,
    addr DECIMAL(39,0) NOT NULL UNIQUE
);

Then I SELECT all ip addresses for each network and record the response time. Average response time on the twobigints table is about 1 second while on the binary table it is about one-hundredth of a second.

Here are the queries.

Note:

X_[HIGH/LOW] is the most/least significant 64-bits of X

when NETMASK_LOW is 0 the AND condition is omitted as it always yields true. doesn't affect performance very much.

SELECT COUNT(*) FROM ipv6_address_twobigints
WHERE haddr & NETMASK_HIGH = NETWORK_HIGH
AND laddr & NETMASK_LOW = NETWORK_LOW

SELECT COUNT(*) FROM ipv6_address_binary
WHERE addr >= NETWORK
AND addr <= BROADCAST

SELECT COUNT(*) FROM ipv6_address_decimal
WHERE addr >= NETWORK
AND addr <= BROADCAST

Average response times:

Average response times

BINARY_InnoDB  0.0119529819489
BINARY_MyISAM  0.0139244818687
DECIMAL_InnoDB 0.017379629612
DECIMAL_MyISAM 0.0179929423332
BIGINT_InnoDB  0.782350552082
BIGINT_MyISAM  1.07809265852
like image 114
Jake Avatar answered Feb 22 '23 10:02

Jake