首页 > 解决方案 > ip2long("012.012.012.012") 在 Linux 上返回 false

问题描述

假设 IPv4 地址表示中有前导零,例如012.012.012.012.

为了抑制前导零,我只需编写以下代码,它就可以在我的 Mac 上按预期工作:

% php -r 'var_dump(long2ip(ip2long("012.012.012.012")));'
Command line code:1:
string(11) "12.12.12.12"

% php --version
PHP 7.3.25 (cli) (built: Dec 25 2020 22:03:38) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.25, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.25, Copyright (c) 1999-2018, by Zend Technologies
    with Xdebug v3.0.1, Copyright (c) 2002-2020, by Derick Rethans

但是这段简单的代码在 CentOS 7 上不起作用,它似乎ip2long("012.012.012.012")返回false值:

$ php -r 'var_dump(long2ip(ip2long("012.012.012.012")));'
string(7) "0.0.0.0"

$ php --version
PHP 7.3.25 (cli) (built: Nov 24 2020 11:10:55) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.25, Copyright (c) 1998-2018 Zend Technologies

$ cat /etc/redhat-release
CentOS Linux release 7.8.2003 (Core)

两个 PHP 版本是相同的,我希望它们返回完全相同的值。我还阅读了ip2long 文档,并试图找出这种行为是否有任何特殊选项/配置,但没有运气。

有人能引导我走向正确的方向吗?是什么让他们与众不同?我该怎么办?

标签: phpip2long

解决方案


好吧,我找到了罪魁祸首。正如Russ-san 评论的那样,LLVM 和 GCC 之间的不同实现inet_pton(3)导致了这种行为。6 年前有一个关于完全相同问题的错误报告。似乎 PHP v5.2.10 已经开始使用而不是根据这个补丁,这就是为什么旧版本的 PHP将每个块视为八进制的原因。inet_ptoninet_addr

测试.c

#include <stdio.h>
#include <arpa/inet.h>

#define INADDR "012.012.012.012"

int main() {
    struct in_addr inaddr;

    if (inet_pton(AF_INET, INADDR, &inaddr) == 0) {
        printf("Invalid: %s\n", INADDR);
    }
    else {
        printf("Valid: %s\n", INADDR);
    }

    return 0;
}
  • 苹果电脑
% cc test.cc && ./a.out
Valid: 012.012.012.012
  • Linux
$ cc test.cc && ./a.out
Invalid: 012.012.012.012

我放弃了使用ip2long/long2ip内置函数,现在尝试使用https://github.com/mlocati/ip-lib

>>> \IPLib\Address\IPv4::fromString("1.2.3.12")->toString(true);
=> "001.002.003.012"
>>> \IPLib\Address\IPv4::fromString("001.002.003.012")->toString();
=> "1.2.3.12"

到目前为止没有问题。


推荐阅读