ip2long("012.012.012.012") возвращает false в Linux

Предположим, что в представлении адреса 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 и попытался найти, есть ли какие-либо специальные параметры/конфигурации для этого поведения, но безуспешно.

Может ли кто-нибудь вести меня в правильном направлении? Чем они отличаются? А что мне делать?

1 ответ

Хорошо, я нашел виновника. Различная реализация inet_pton(3)между LLVM и GCC ведет такое поведение, как прокомментировал Русс-сан . Был баг-репорт о точно такой же проблеме 6 лет назад. Кажется, PHP v5.2.10 начал использовать inet_ptonвместо inet_addrсогласно , поэтому этому патчуболее старые версии PHP обрабатывают каждый фрагмент как восьмеричный.

тест.с

      #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
  • линукс
      $ 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"

Пока никаких проблем.

Другие вопросы по тегам