Meestal geef je gratis verzending in een webshop wanneer een bepaalde prijs is bereik.
Voor een website, onder mijn beheer, ging deze stelling niet op. En meer zelfs, verzending naar het buitenland is duurder en hoe groter (zwaarder) het pakket hoe hoger de verzendkosten.

Om de gebruiker bij het afrekenen niet op te zadelen met een verzend verassing is het nodig om vooraf al te weten van welk land de gebruiker is.
Dit kan via de gegevens van de browser. In de Accept-Language header is wel het één en ander te vinden. Maar ik vond dit niet goed genoeg.
Een andere oplossing is gebruik te maken van een IP geolocation service.
Maar er zijn op het internet gratis lijsten te downloaden die IP-ranges bevatten met een verwijzing naar een land.

De data die ik ga verwerken is deze "0","281470681743359","-","-" "281470681743360","281470698520575","-","-" "281470698520576","281470698520831","US","United States of America" "281470698520832","281470698521599","CN","China" .... "281474976710656","42540528726795050063891204319802818559","-","-" "42540528726795050063891204319802818560","42540528727168608142152124734787026943","JP","Japan" "42540528727168608142152124734787026944","42540528727169817067971739363961733119","US","United States of America" "42540528727169817067971739363961733120","42540528727252024023705534147841753087","JP","Japan"

Hier is het eerste veld de start van de range, het tweede veld de stop, het derde de ISO-code (2 karakters) van het land.
Het vierde veld gaan we niet gebruiken, want we hebben al lang een Country tabel op onze systemen.

Hoe krijg je dit nu in een database om bv te weten te komen of het IP adres '2a05:1500:702:0:1c00:7aff:fe00:92' van nederland is?

Ten tijde van IPv4 kon je alles nog bewaren als een bigint in een tabel, maar met IPv6 schiet je te kort.
Het meest logische is gebruik te maken van een varbinary(16). Zo kan er op een efficiente manier 4 bytes gebruikt worden voor IPv4 gegevens en de 16 voor IPv6.

Verder zullen we gebruik maken van de INET6_ATON en de INET6_NTOA functies.
Alvast hierbij de opmerking dat deze methodes razend snel zijn en bijna niet leiden tot een vertraging.

DROP TABLE IF EXISTS `iptocountryv6`;
CREATE TABLE `iptocountryv6` (
	 `id` bigint NOT NULL auto_increment,
	 `start` varbinary(16) NOT NULL,
	 `stop` varbinary(16) NOT NULL,
     `iso_code` char(2) NOT NULL,
	PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Voor de overgang van zo'n numerieke string naar een IPv6 heb ik geen functie gevonden, maar met BCMath kan zoiets gemakkelijk omgezet worden private static function inet_itop($decimal) { $parts = []; $parts[1] = bcdiv($decimal, '79228162514264337593543950336', 0); $decimal = bcsub($decimal, bcmul($parts[1], '79228162514264337593543950336')); $parts[2] = bcdiv($decimal, '18446744073709551616', 0); $decimal = bcsub($decimal, bcmul($parts[2], '18446744073709551616')); $parts[3] = bcdiv($decimal, '4294967296', 0); $decimal = bcsub($decimal, bcmul($parts[3], '4294967296')); $parts[4] = $decimal; foreach ($parts as &$part) { // convert any signed ints to unsigned for pack // this should be fine as it will be treated as a float if ($part > 2147483647) $part -= 4294967296; } $ip = inet_ntop(pack('N4', $parts[1], $parts[2], $parts[3], $parts[4])); return $ip; }

Eens je de IP-adresen hebt kan je ze toevoegen aan de mySQL databank. Deze zal via de INET6_ATON functie de IP string omzetten naar een binary string $stmt = $mysqli->prepare("INSERT INTO `iptocountryv6` (`start`,`stop`,`iso_code`) VALUES (INET6_ATON(?), INET6_ATON(?), ?)"); $stmt->bind_param('sss',$startIp, $stopIp, $country);

Om te zoeken naar het land waartoe een IP behoord kunnen we met een Between gaan zoeken.

select * from `iptocountryv6` 
            where INET6_NTOA(`iptocountryv6`.`start`) <= INET6_NTOA(INET6_ATON('2a05:1500:702:0:1c00:7aff:fe00:92'))
            and INET6_NTOA(`iptocountryv6`.`stop`) >= INET6_NTOA(INET6_ATON('2a05:1500:702:0:1c00:7aff:fe00:92'))

Misschien kan er her en der nog wat gesleuteld worden aan optimalisatie, indexen etc. Maar op deze manier is het zeker werkbaar.

Tags gerelateerd aan dit artikel:

Blog Categorie