30

I often hear people say to use "$_SERVER['SERVER_ADDR']", but that returns the LAN IP of my server (e.g. 192.168.1.100). I want the external IP.

Leo Jiang
  • 24,497
  • 49
  • 154
  • 284

12 Answers12

67

There is NO way to get your underlying IP Address that has been designated by your ISP via conventional PHP if you are using a router. A way to get the external IP is to find a service that will obtain it for you and echo the address back to you. I found a handy service which does just that. http://ipecho.net/

You can use:

$realIP = file_get_contents("http://ipecho.net/plain");
Jason
  • 15,017
  • 23
  • 85
  • 116
Ben
  • 779
  • 5
  • 2
  • 3
    Using ipecho.net is much nicer than parsing an HTML response. This answer should be considered as the new accepted answer. – Arnold Daniels Dec 08 '15 at 23:42
  • 2
    The first two sentences contradict each other. There can't be "no way" and then an "only way". Also, "ONLY" is a **very** strong word there. – jeteon May 12 '16 at 03:05
45

Just query a host that returns your IP address:

$externalContent = file_get_contents('http://checkip.dyndns.com/');
preg_match('/Current IP Address: \[?([:.0-9a-fA-F]+)\]?/', $externalContent, $m);
$externalIp = $m[1];

or, set up a service that simply echoes just the IP, and use it like this:

$externalIp = file_get_contents('http://yourdomain.example/ip/');

Set up the service yourself by simply echoing the remote IP address, or pay someone to host it. Do not use somebody else's server without permission. Previously, this answer linked to a service of mine that's now being hit multiple times a second.

Note that in an IP network with one or more NATs, you may have multiple external IP addresses. This will give you just one of them.

Also, this solution of course depends on the remote host being available. However, since there is no widely implemented standard (no ISP and only some home routers implement UPnP), there is no other way to get your external IP address. Even if you could talk to your local NAT, you couldn't be sure that there isn't another NAT behind it.

phihag
  • 278,196
  • 72
  • 453
  • 469
  • 16
    Oh yeah and what if that website is offline? That's right, you'll be screwed to death. –  Oct 26 '11 at 22:01
  • @WTP Well, you could certainly fallback to another address. But in general, there is no other way if you're behind a NAT or some other kind of tunnel. – phihag Oct 26 '11 at 22:03
  • If there is functionality within your application where the remote IP address is vital, it should be set within a configuration somewhere rather than by an external service. – Patrick Moore Oct 26 '11 at 22:12
  • @SetSailMedia Or, even better, don't ever require your "public IP address" at all. Any remote host already knows your address. – phihag Oct 26 '11 at 22:15
  • whatismypi.org has changed it's response to an image (no text on the page to use anymore), so it's not useful for this hack anymore. I hope nobody really was relying on it... – Nilloc Mar 06 '13 at 16:41
  • @Nilloc Updated, with an explanation of why this hack is the only possible solution. – phihag Mar 06 '13 at 17:34
  • 1
    This is 'the sad truth'. Forget superglobals, environment variables or host associated IP's, making 'real' contact is the only way to get the actual IP. – kasimir Sep 01 '14 at 08:15
  • Why do you need `[` before `0` and a final `<` in the pattern? I think these 2 characters are useless. – François Jan 16 '15 at 01:47
  • 1
    @François The `[` is to allow brackets which are often used to delimit IPv6 addresses. The final `<` is indeed optional, and makes the code more robust if the format should change. – phihag Jan 16 '15 at 12:32
  • @user142019 It seems, that this is the only working and reliable solution. Not 100% reliable, but rather highly reliable and working... You don't like it, fine. But, instead of just crying about possible scenarios, when you're going to be screwed, maybe you could come with something more reliable? – trejder Jun 17 '15 at 07:22
7

I'm going to add a solution because the others weren't quite right for me because they:

  • need to be run on a server with a domain name e.g. gethostbyname() (if you think about it, you don't actually have the problem if you know this a priori)
  • can't be used on the CLI (rely on something in $_SERVER to be set by a web server)
  • assume a specific format of ifconfig output, which can include multiple non-public interfaces
  • depend on parsing someone's website (who may disappear, change the URL, change the format, start lying to you, etc, all without notice)

This is what I would suggest:

$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
$res = socket_connect($sock, '8.8.8.8', 53);
// You might want error checking code here based on the value of $res
socket_getsockname($sock, $addr);
socket_shutdown($sock);
socket_close($sock);

echo $addr; // Ta-da! The IP address you're connecting from

The IP address there is a Google public DNS server. I trust they'll be around and running it for a while. It shouldn't really matter what address you use there as long as its a public IP address that belongs to someone who doesn't mind random connection attempts too much (yourself maybe?).

This is based on an answer I came across when I had a similar problem in Python.


P.S.: I'm not sure how well the above would work if there is sorcery going on between your machine and the internet.

Community
  • 1
  • 1
jeteon
  • 3,471
  • 27
  • 40
6

You could parse it from a service like ip6.me:

<?php

// Pull contents from ip6.me
$file = file_get_contents('http://ip6.me/');

// Trim IP based on HTML formatting
$pos = strpos( $file, '+3' ) + 3;
$ip = substr( $file, $pos, strlen( $file ) );

// Trim IP based on HTML formatting
$pos = strpos( $ip, '</' );
$ip = substr( $ip, 0, $pos );

// Output the IP address of your box
echo "My IP address is $ip";

// Debug only -- all lines following can be removed
echo "\r\n<br/>\r\n<br/>Full results from ip6.me:\r\n<br/>";
echo $file;
Patrick Moore
  • 13,251
  • 5
  • 38
  • 63
  • 2
    As in description on ip6.me page, you should rather use `ip4.me` site instead, because your (your customer's) browser may not have IPv6 connectivity and display `Page not found` in this case. – trejder Jun 17 '15 at 07:35
4

You could try this:

$ip = gethostbyname('www.example.com');
echo $ip;

to get the IP address associated with your domain name.

trejder
  • 17,148
  • 27
  • 124
  • 216
jakx
  • 748
  • 5
  • 8
  • This is incorrect as it's getting the ip address of the domain you're pinging it seems like? – Omar Jul 20 '18 at 16:52
  • It IS correct. Not sure why there are so many convoluted answers. Seems this should be the accepted one. For portability: $ip = gethostbyname($_SERVER['HTTP_HOST']); – Eric P Aug 25 '19 at 06:50
1

I know this question is old and long answered, but I was googling for the same thing and want to add my own "hack". For this to work your webrequest has to come from an external IP address or you have to alter $own_url to a url that does an external request to itself.

The point is, if you let the script do a request to itself than you get it's external IP address.

<?php
if (isset($_GET['ip'])) {
    die($_SERVER['REMOTE_ADDR']);
}
$own_url = (isset($_SERVER['HTTPS']) ? 'https' : 'http') . '://'.$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME'];
$ExternalIP = file_get_contents($own_url.'?ip=1');
echo $ExternalIP;
?>
Martin
  • 1,184
  • 8
  • 24
  • This won't work if your nameservers are like Cloudflare, CloudDNS etc. It will return the IP from the main cloud nameserver, not your server's. – Konstantinos Feb 07 '22 at 11:29
1

I think there is much code for this things in others answers, but my answer is short, but you need to execute a command in shell to get the ip...

but it is short and fast, I think that...

php execute bash > bash run > bash get ip > php get ip

echo shell_exec( "dig +short myip.opendns.com @resolver1.opendns.com");

Sorry my for my english, I hope it help all you...

Reference: How can I get my external IP address in a shell script?

DarckBlezzer
  • 4,578
  • 1
  • 41
  • 51
1

This is an old thread, but for what it's worth, I'm adding a simple function that I use. It uses outside services (which is inevitable it seems), but it provides a backup service as well, and local caching to avoid repetitive HTTP calls.

/*
USAGE
$ip = this_servers_public_ip(); // Get public IP, and store it locally for subsequent calls.
$ip = this_servers_public_ip(true); // Force remote query and refresh local cache if exists.
*/
function this_servers_public_ip($purge=false) {
    $local = sys_get_temp_dir().'/this.servers.public.ip';
    if ( $purge===true && realpath($local) ) {
        unlink($local);
    }
    if ( realpath($local) ) {
        return file_get_contents($local);
    }
    // Primary IP checker query.
    $ip = trim( file_get_contents('https://checkip.amazonaws.com') );
    if ( (filter_var($ip, FILTER_VALIDATE_IP) !== false) ) {
        file_put_contents($local,$ip);
        return $ip;
    }
    // Secondary IP checker query.
    $ip_json = trim( file_get_contents('https://ipinfo.io/json') );
    $ip_arr = json_decode($ip_json,true);
    $ip=$ip_arr['ip'];
    if ( (filter_var($ip, FILTER_VALIDATE_IP) !== false) ) {
        file_put_contents($local,$ip);
        return $ip;
    }
    return false; // Something went terribly wrong.
}
Eric P
  • 588
  • 5
  • 9
0

If your server have a domain name you can ping it or you can use:

$sMyServerIP = gethostbyname('yourdomain.com');
echo $sMyServerIP;

It will return your outer IP address.

Codebeat
  • 6,501
  • 6
  • 57
  • 99
0

Assuming your PHP is running on a Linux server you can call ifconfig using PHP's exec function. This will give public IP without need to contact some external website/service. E.g.:

$command = "ifconfig";  /// see notes below
$interface = "eth0";    // 
exec($command, $output);
$output = implode("\n",$output);
if ( preg_match('/'.preg_quote($interface).'(.+?)[\r\n]{2,}/s', $output, $ifaddrsMatch)
        && preg_match_all('/inet(6)? addr\s*\:\s*([a-z0-9\.\:\/]+)/is', $ifaddrsMatch[1], $ipMatches, PREG_SET_ORDER) )
{
    foreach ( $ipMatches as $ipMatch ) 
        echo 'public IPv'.($ipMatch[1]==6?'6':'4').': '.$ipMatch[2].'<br>';
}

Note that sometimes as $command you have to specify full path of ifconfig. You can find this by executing

whereis ifconfig

from shell prompt. Furthermore $interface should be set to the name of your server's main network interface that has the link to the WAN.

On Windows you can do something similar of course, using ipconfig instead of ifconfig (and corresponding adjusted regex).

Arthur
  • 584
  • 6
  • 14
0

Also you could get IP via DNS A record based on hostname or server name:

$dnsARecord = dns_get_record($_SERVER['HTTP_HOST'],DNS_A);
if ( $dnsARecord ) echo 'IPv4: '.$dnsARecord[0]['ip'];
$dnsARecord = dns_get_record($_SERVER['HTTP_HOST'],DNS_AAAA);
if ( $dnsARecord ) echo 'IPv6: '.$dnsARecord[0]['ip'];

You could also use SERVER_NAME instead of HTTP_HOST if one of the two does not give what you want.

However, this is assuming that your server is configured correctly in correspondence with DNS. This may not always be the case. See my other answer using ifconfig that is perhaps better.

Arthur
  • 584
  • 6
  • 14
-3

Have you tried:

gethostbyname(php_uname('n'));

?

  • `php_uname('n')` returns in most cases the **internal** IP address, i.e. LAN-based. OP's asking for an **external** one. – trejder Jun 17 '15 at 07:27