问题
I know that this question has been asked quite a few times, but I could not find anywhere a final resolution; so here goes:
How do you store an IP (both IPv4 and IPv6) using best-practice, within a DB, without knowing the DB? This in case for DB abstraction purposes, such as PHP PDO.
On a minor note, I have PHP 5.2.17, as I needed PEAR on windows.
People have been suggesting to store it as a varbinary(16) and use mysql functions inet6_ntop and inet6_pton to pass IPs back and forth as strings; like Extending MySQL 5 with IPv6 functions is suggesting. In PHP, the functions inet_pton() and inet_ntop() can convert IPv4 and IPv6 back and forth to binary format as ThiefMaster in this question is suggesting, but it is unclear how one would pass binary content into a SQL INSERT/UPDATE string (and these php functions are only provided with php 5.3.0 on windows, even though it is possible to reverse engineer these). I really like what Jake did and his results with regards to integer representations of IPs in DBs, and this may come in handy in some distant, unforeseen future, if I were to implement this into my DB, but then I'm unsure about DB cross-compatibilities for DB abstraction using PHP PDO. This post seems to provide a close answer about storing binary values, but isn't unescaped binary injection into strings a potential hazard? Also, if you follow this route, how many DBs can convert a varbinary(16)/int(128bit) into a representational IP, if some developer wanted to do some quick lookups?
It seems to me that the most simple way is to insert the ip string as-is into a varchar(45). But how would those who want to follow the complicated route, in PHP (reverse-engineered as djmaze(AT)dragonflycms(.)org or as MagicalTux at FF dot st is suggesting) using the inet_ntop() and inet_pton() functions, store and retrieve an IPv6 as binary? Can someone give an example using PDO from <?php $strIP = "2001:4860:b002::68"; ?>
, using an INSERT and then SELECT prepared statements?
As you can see, I've done my research, but the ultimate good-practice of this IPv6 isn't clear to me.
回答1:
Like your research shows there are benefits and problems with storing IP addresses as strings in canonical form, binary strings or as integers. Maybe there is a middle ground to store IP addresses in a database.
How about storing them as strings, but expanded to the full maximum length. That way you can still compare them (==, >, <, etc) but they are also still readable and you don't need special input and output encoding of special characters.
An example of how you could do this:
function expand_ip_address($addr_str) {
/* First convert to binary, which also does syntax checking */
$addr_bin = @inet_pton($addr_str);
if ($addr_bin === FALSE) {
return FALSE;
}
/* Then differentiate between IPv4 and IPv6 */
if (strlen($addr_bin) == 4) {
/* IPv4: print each byte as 3 digits and add dots between them */
return implode('.', array_map(
create_function('$byte', 'return sprintf("%03d", ord($byte));'),
str_split($addr_bin)
));
} else {
/* IPv6: print as hex and add colons between each group of 4 hex digits */
return implode(':', str_split(bin2hex($addr_bin), 4));
}
}
And some examples:
/* Test IPv4 */
var_dump(expand_ip_address('192.0.2.55'));
/* Test IPv6 */
var_dump(expand_ip_address('2001:db8::abc'));
/* Test invalid */
var_dump(expand_ip_address('192:0:2:55'));
Which produce:
string(15) "192.000.002.055"
string(39) "2001:0db8:0000:0000:0000:0000:0000:0abc"
bool(false)
来源:https://stackoverflow.com/questions/14427621/best-way-to-store-an-ipv6-in-unknown-db