Ben Harold
Ben Harold

Reputation: 6432

How can I convert this string into a human readable IP address in PHP?

I've got a string representing an IPv4 address:

$ip = '\x7F\0\0\x01';

When I try to pass that to inet_ntop($ip) it's giving me grief:

PHP Warning: inet_ntop(): Invalid in_addr value

If I declare the variable manually using double quotes it works:

$ip = "\x7F\0\0\x01";
inet_ntop($ip); // "127.0.0.1"

However, I am not declaring these variables manually. I'm working with what is given to me in an object.

How can I convert '\x7F\0\0\x01' into a string that inet_ntop() will accept?

In other words, how can I make PHP parse a string literally as if I were manually declaring it with double quotes?


Some interesting facts:

gettype('\x7F\0\0\x01'); // string
gettype("\x7F\0\0\x01"); // string
ord('\x7F\0\0\x01'); // 92
ord("\x7F\0\0\x01"); // 127
implode(unpack('H*', '\x7F\0\0\x01')); // 5c7837465c305c305c783031
implode(unpack('H*', "\x7F\0\0\x01")); // 7f000001
mb_detect_encoding('\x7F\0\0\x01'); // ASCII
mb_detect_encoding("\x7F\0\0\x01"); // UTF-8
"\x7F\0\0\x01" == '\x7F\0\0\x01'; // false
// and for the haters
long2ip('\x7F\0\0\x01'); // PHP Warning:  long2ip() expects parameter 1 to be integer, string given

Upvotes: 0

Views: 677

Answers (3)

ramsey
ramsey

Reputation: 637

The problem is that you've got the literal ASCII output of a binary string and not the real binary value you expect it to be. I'm not sure how you got the literal ASCII value. There is a way to convert it, but you're not going to like it.

You can use eval() to accomplish what you're trying to do. All arguments for eval() being evil still apply.

$ip = '\x7F\0\0\x01';
eval("\$ip = \"$ip\";");
echo inet_ntop($ip);

This will print out 127.0.0.1.

Since binary doesn’t always result in literal ASCII characters, I worry you’ll see literal characters like � in the strings, and these won’t convert properly to the binary value you expect them to be.

For example, here are the characters printed to screen in Psysh:

>>> hex2bin('7f000001') // This is 127.0.0.1
=> "\x7F\0\0\x01"
>>> hex2bin('ffffffff') // This is 255.255.255.255
=> b"ÿÿÿÿ"

The first value looks familiar, right? That's the string literal that we can convert back into a binary string using eval(), like we did in the example above. But the binary value for ffffffff is a different story. If we try to convert it, it doesn't give us the 255.255.255.255 value we expect.

$ip = 'ÿÿÿÿ';
eval("\$ip = \"$ip\";");
echo inet_ntop($ip);

In this case, inet_ntop() returns false, but we know it should work:

>>> inet_ntop(hex2bin('ffffffff'));
=> "255.255.255.255"

So, I worry that any attempt to convert these values from string literals into binary strings is not going to work in all cases, whether using eval() or any of the other answers provided here.

However, if everything is coming to you in the format \0\0\0\0, where each "segment" is either a zero or a hex value in the format x00, then you should be in good shape, because these are the same:

>>> "\xFF\xFF\xFF\xFF"
=> b"ÿÿÿÿ"

Upvotes: 1

Yovi Prasetyo
Yovi Prasetyo

Reputation: 212

You can make your own function like this

function convertStringToInAddr(string $string) {
    $return = null;
    $exploded = explode("\\", $string);
    foreach($exploded as $hex) {
        if( $hex != "" ) {
            $return .= chr(hexdec(str_replace("x", "", $hex)));
        }
    }
    return $return;
}

Upvotes: 0

Nick
Nick

Reputation: 147206

One possibility is to parse the string into its component pieces (starting with \); convert them to the decimal equivalent and use chr to get back the original characters. These can then be joined into a string which is suitable for inet_ntop:

$ip = '\x7F\0\0\x01';
preg_match_all('/\\\x?([\dA-F]+)/', $ip, $parts);
$ip = implode('', array_map(function ($v) { return chr(hexdec($v)); }, $parts[1]));
echo inet_ntop($ip);

Another alternative is to use pack, after stripping out the \x parts and replacing \0 with 00:

$ip = '\x7F\0\0\x01';
$ip = pack('H*', str_replace(array('\x', '\0'), array('', '00'), $ip));
echo inet_ntop($ip);

In both cases the output is:

127.0.0.1

Demo on 3v4l.org

Upvotes: 2

Related Questions