6

Sander Steffann我之前的问题中提到:

像 0000:0000:0000:0000:0000:0000:192.168.0.1 这样的地址写成 0000:0000:0000:0000:0000:0000:c0a8:0001 ,这是完全相同的地址,但使用十六进制表示法。

我如何在 PHP 中检测地址是否写成例如:::0000:192.168.0.10000::0000:192.168.0.10000:0000:0000:0000:0000:0000:192.168.0.1?检查基于 IP 的字符串是否有 '.' 是否足够?和 ':' ?

以及如何将其更改为完整字符串0000:0000:0000:0000:0000:0000:c0a8:0001

我是否正确,将其更改为 IPv4 将类似于:

<?php 
$strIP = '0000:0000:0000:0000:0000:0000:192.168.0.1';

$strResult = substr($strIP, strrpos($strIP, ':'));

echo $strResult; //192.168.0.1 ?
?>

...还是正确的 IP 字符串表示比这个片段可以做的更复杂?

4

3 回答 3

3

我不敢相信我一口气写完了这一切,而且第一次就奏效了。

$strIP = '0000:0000:0000:0000:0000:0000:192.168.0.1';
$arrIP = explode(':', $strIP);

if( preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/', $arrIP[count($arrIP)-1]) ) {
  $ip4parts = explode('.', $arrIP[count($arrIP)-1]);
  $ip6trans = sprintf("%02x%02x:%02x%02x", $ip4parts[0], $ip4parts[1], $ip4parts[2], $ip4parts[3]);
  $arrIP[count($arrIP)-1] = $ip6trans;

  $strIP = implode(':', $arrIP);
}
echo $strIP; //output: 0000:0000:0000:0000:0000:0000:c0a8:0001

基本上:

  1. 爆炸字符串:
  2. 检查最后一个四边形的格式是否像 IP4 地址
  3. 爆炸最后一个四边形.
  4. 将 IP4 八位字节重新打印成两个十六进制四边形
  5. 用新的替换 IP4 quad
  6. 在 上内爆数组:
于 2013-01-21T19:23:10.267 回答
3

您最好的选择是不要手动执行此操作,而是调用inet_pton以获取二进制表示,然后将其转换为您希望拥有的格式。

$foo = inet_pton("::1");
for ($i = 0 ; $i < 8 ; $i++)
    $arr[$i] = sprintf("%02x%02x", ord($foo[$i * 2]), ord($foo[$i * 2 + 1]));
$addr = implode(":", $arr);
于 2013-01-21T19:37:05.963 回答
2

首先:你为什么要关心地址是怎么写的?inet_pton() 将为您解析所有变体并为您提供一致的结果,然后您可以将其转换为二进制、十六进制或任何您想要的。

所有用于转换之类的代码::192.168.0.1实际上0000:0000:0000:0000:0000:0000:c0a8:0001都在我的帖子中。这正是我的示例函数所做的。

如果您0000:0000:0000:0000:0000:0000:192.168.0.1先输入 inet_pton(),然后再输入 inet_ntop(),您将获得规范的 IPv6 表示法,::192.168.0.1在这种情况下就是这样。如果该字符串以开头::并且其余包含 no:和三个点,那么您可以确定它是 IPv4 地址;-)

要将上一个问题的答案与此问题相结合:

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;
  }

  $addr_hex = bin2hex($addr_bin);

  /* See if this is an IPv4-Compatible IPv6 address (deprecated) or an
     IPv4-Mapped IPv6 Address (used when IPv4 connections are mapped to
     an IPv6 sockets and convert it to a normal IPv4 address */
  if (strlen($addr_bin) == 16
  &&  substr($addr_hex, 0, 20) == str_repeat('0', 20)) {
    /* First 80 bits are zero: now see if bits 81-96 are either all 0 or all 1 */
    if (substr($addr_hex, 20, 4) == '0000')
    ||  substr($addr_hex, 20, 4) == 'ffff')) {
      /* Remove leading bits so only the IPv4 bits remain */
      $addr_bin = substr($addr_hex, 12);
    }
  }

  /* Then differentiate between IPv4 and IPv6 */
  if (strlen($addr_bin) == 4) {
    /* IPv4: print each byte as 3 digits and add dots between them */
    $ipv4_bytes = str_split($addr_bin);
    $ipv4_ints = array_map('ord', $ipv4_bytes);
    return vsprintf('%03d.%03d.%03d.%03d', $ipv4_ints);
  } else {
    /* IPv6: print as hex and add colons between each group of 4 hex digits */
    return implode(':', str_split($addr_hex, 4));
  }
}
于 2013-01-21T21:27:08.727 回答