Convert network ip to ip2long

I need to convert some ip data with this format to start_num and end_num with ip2long format:
1.251.248.0/24
125.129.185.0/24
Does the first one mean that 1.251.248.0 is start_num? what would be end_num? and for second one 125.129.185.0 is start_num and what is end_num?
Actually my question is that the number after / is the 4th part of the same ip for end_num and the ip before / is start_num?
Is this 125.129.185.0/24 format called “CIDR”?

It’s standard subnet notation.

/24 defines the size of the network - in this case, a standard 24.

There are 32 bits in an IPV4 address. 24 identifies the number of bits that define the network (the first 24), and leaves the remainder as individual host/machine identifiers.

1.251.248.0/24 tells you that the network is “1.251.248” (or, in binary, 000000011111101111111000), and leaves the last 8 bits to be assigned to individual hosts - namely, from 1.251.248.0 (usually a reserved address) to 1.251.248.255 - 00000000 to 11111111.

IP 2 Long formula would be:
Determine number of network bits (slice off the bit after the /).
Convert INT’s to binary. Slap them together in a string. (at this point, you have the IP as a binary string, which can be translated to a long for the long of a specific IP)
Sever the string at the split point; keep the first half.
Start num = the long-converted number represented by the first half of the string, padded to length 32 with 0’s.
End num = the long-converted number represented by the first half of the string, padded to length 32 with 1’s.

Actually I asked how will I know the ending range of 109.70.67.80/28 will be 109.70.67.95? how this is calculated that we got 95?

Code to work with subnets would use bit masking, so a good place to start would be Bitwise Operators

and what is the formula that I can use it with bitwise operator? can you write a code block to convert cidr to start/end range that I understand formula?

Not me. That’s an area I consider “advanced” only because it take great effort and concentration for me to even begin to get my head around it.

IMHO if you can learn how you’ll be ahead of the majority of PHP coders.

ahead of the majority of PHP coders.

really? or you are just joking?

No joke. I see very little PHP code here that uses bitwise operators.
And very little anywhere for that matter.

Not that it is always applicable, but there are times when using bitwise would result in more efficient code in less lines (albeit not more readable).

I could be wrong, but my feeling is this is because most PHP coders don’t understand it and so don’t use it.

I… just laid that out for you.

You can just as easily reverse the int-to-binary part to retrieve the 4-dot notation form.

1 Like

I understood the formula to calculate IP ranges given CIDR, but I could do calculate it manually, not with php and then found this: https://gist.github.com/jonavon/2028872

if database just has cidr column, is it possible to found just a REMOTE_ADDR in database converting just that ip into cidr? I doubt, but clarify if I am wrong, so I think better to have start_num and end_num columns in db to found REMOTE_ADDR country?

It… is theoretically doable (you’d have to convert the database’s CIDR into a range at Query Time. Not fun), depending on the database system being used, but you’ll find it a lot simpler with start/end fields - a simple BETWEEN clause.

Such datasets already exist, by the way. Sites like MaxMind do free ones, though the accuracy is not guaranteed and free versions require attribution.

maxmind gives 2 geoname_id for each ip, represented_id and registered_id, they might be in 2 different countries, but I didn’t understand which one would be website visitor location? if you want to see where REMOTE_ADDR or website visitor is actually located which one should you check? represented_id or registered_id?

how to convert ipv6 into long integer (just like what ip2long does for ipv4) ?

You could do similar using what you’ve learned from the github gist you linked to.

IPv6 addresses are represented as eight groups of four hexadecimal digits with the groups being separated by colons, for example 2001:0db8:85a3:0042:1000:8a2e:0370:7334

You still have groups of bits, just more of them and they’re in hexidecimal representing binary instead of decimal.

This means just removing : and simply convert hex to dec?
or this means multiplying by power of 65535 each group and add them altogether (just like what does ip2long: multiplying by power of 256)?

Times 256 is decimal to binary. I guess you could do hex → dec _> bin, but you could just use
base_convert()) to go directly to binary.

There are a couple of gotchas here too - you need to make sure the address is properly formatted. It is deemed “ok” to shorthand 0’s in the sequence in the following two ways:

  • Leading Zeros May Be Omitted

  • A single block of 2 or more groups of all-zeros may be shorthanded as double colon.

2001:0db8:85a3:0042:1000:0000:0000:7334
May be represented as
2001:db8:85a3:42:1000::7334
or
2001:0db8:085a3:42:1000::7334
or
2001:db8:85a3:42:1000:0:0:7334

ipv6 addresses can be as short as
::1
(0000:0000:0000:0000:0000:0000:0000:0001)

  1. Do you mean if I want to convert this to integer:
    2001:db8:85a3:42:1000::7334
    first I need to convert it to
    2001:0db8:85a3:0042:1000:0000:0000:7334
    then just convert this to decimal, by base_convert($ip6v, 16, 10) or so?

  2. another question, if we have:
    2001:0000:85a3:0042:1000:0000:0000:7334
    then we can write it as:
    2001::85a3:0042:1000::7334
    as we write just :: how will we know if it was:
    2001:0000:0000:85a3:0042:1000:0000:7334
    or it was:
    2001:0000:85a3:0042:1000:0000:0000:7334
    ? how will we know that? or that format is invalid? if invalid, how will we know that it is invalid?

  3. As you said for ip4v:

1.251.248.0/24 tells you that the network is “1.251.248” (or, in binary, 000000011111101111111000), and leaves the last 8 bits to be assigned to individual hosts - namely, from 1.251.248.0 (usually a reserved address) to 1.251.248.255 - 00000000 to 11111111.

We should do 32-24 = 8 to know how many the last bits are, e.g. 8.
Now what about ip6v cidr? should I calculate with 128? e.g. for: 2c0f:ffd8:1::/48
does this mean: 128 - 48 = 80, and it means the last 80 bits to be assigned to individual host?

Having more than one :: is not valid in an ipv6, because of just what you pointed out; the address becomes indeterminate. There may be only one or zero :: in an address.

And yes, you will need to convert the address to it’s full form (technically. You can theoretically ignore leading zeros on the first group of digits), then remove the :'s (because base_convert has no idea what a colon is when converting a hex string).

HOWEVER. You want to avoid base_convert for these, because the number is so large that base_convert will lose precision in many cases.
Our example, for…well, example:
2001:0000:85a3:0042:1000:0000:0000:7334
Strip the colons to get your hex string.
Base_convert(16,10) tells you that the answer is:

42540488203334400008880468400004062844

but the actual value is

42540488203334405194024465490610516788

Consider looking at the function listed in the top comment on the [BC Math functions][1] page for a function that can be used to go Hex2Dec with arbitrarily large numbers.

As for 3), CIDR would say /X means that X bits of the address are being used as network definitions - keeping in mind that this can be a relative frame of reference. ipv6 would indeed be a 128 bit representation.
[1]: http://php.net/manual/en/ref.bc.php

1 Like