How do I get the external IP of my server using PHP? - php

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.

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");

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.

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.

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;

You could try this:
$ip = gethostbyname('www.example.com');
echo $ip;
to get the IP address associated with your domain name.

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;
?>

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?

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.
}

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.

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).

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.

Have you tried:
gethostbyname(php_uname('n'));
?

Related

php currency setting based on user location

I need to change currency based on user location. This is my code
<?php
$ipaddress = $_SERVER['REMOTE_ADDR'];
$location = unserialize( file_get_contents('http://www.geoplugin.net/php.gp?ip=' . $_SERVER['REMOTE_ADDR']) );
if($location["geoplugin_countryCode"] === "US")
{
// block to set us currency
}
else{
// user can choose their own currency from array (excluding us)
}
?>
I uploaded it on a server, and to check if the functionality works correctly or not and I used different vpn chrome extension. The problem is all the time else part is alone gets executed even when I choose us as vpn server. I don't know What is causing this problem.
Most probably the issue is that you use $_SERVER['REMOTE_ADDR'].
If you are using a proxy, you should use $_SERVER['HTTP_X_FORWARDED_FOR']

login on webpage only from the internet

First of all sorry if my question is dumb or if I use bad terminology but I'm totally new to web programming.
So, I've made an apache server on raspberry pi with few buttons on the webpage to controll lights in my room. I can access it with my home network ip 192.168.xxx.xxx and from internet using my public ip 188.75.xxx.xxx. (just to be clear - the raspi is connected to my router and in the router I'm forwarding port 80 to it)
I want to make some basic login form, but only if I'm connecting trough the 188.75.xxx.xxx ip. And if I'm conencting trough the 192.168.xxx.xxx the form will not show.
Is there any way to achieve this?
Thanks,
Adam N.
When the script is executed, check the IP address before showing anything to the user. Read here about the procedure. Once you have an IP address, you can parse it and see the first two groups. Try something like this to do that. Then compare the numbers and decide to grant or deny permission to access the page. Here you can read about login form in PHP. In pseudo code, that would look like that:
// this is pseudo code, don't try to run it - it will not work
$ip = get_ip();
$groups = parse_ip($ip);
if ( is_home_network($groups) )
{
grant_permissions();
}
else
{
request_login();
}
You can use the PHP filter_var Function with the validate filter FILTER_VALIDATE_IP and the flag filter FILTER_FLAG_NO_PRIV_RANGE.
Code Example:
if ( filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE) )
{
// is not a local ip address
}
I hope i could help you.

Invalid IP Address with multi-line IP Address

I am stuck with this error while trying to read a file which holds IP addresses separated by a new line. What I want to do, is to read my file that holds bunch of IP's and check does they have proper record. This is my code:
$file = "test.sh";
if (is_file($file) && is_readable($file)) {
$get_file_data = file_get_contents($file);
$turn_to_array = explode("\n", $get_file_data);
foreach ($turn_to_array as $key => $value) {
if (filter_var($value, FILTER_VALIDATE_IP)) {
echo gethostbyaddr(trim($value));
} else {
echo "IP invalid";
}
}
}
My test.sh file looks like following:
EDIT :
example IP's
180.1.1.1
181.1.1.2
Do I need to add some specific tests to parse a file or there is some other issue?
The error caused by the very unique method used:
Warning: gethostbyaddr(): Address is not a valid IPv4 or IPv6 PHP
Solved.
My code was working, I wasn't getting rdns record properly, since it didn't exist for those IP's. I've checked it with host 185.1.1.1 and it returned actual IP not domain. Then checked IP's for whom I was sure that they have PTR records, and it woked. But I am not sure exactly how error was fixed actually.
I'm going to be honest, I think exploding the raw file data and hoping for the best may not be the best way to accomplish this. Instead, you should try to extract the exact data you need using regular expressions so you are certain you are extracting the correct values.
Try something like this:
$data = file_get_contents($file);
// This regex matches things that resemble an IP4 address
if (preg_match_all("/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/", $data, $addresses)) {
foreach ($addresses as $address) {
// Need to verify it ACTUALLY is a valid IP address
if (filter_var($address, FILTER_VALIDATE_IP)) {
echo gethostbyaddr($address);
}
}
}
NOTE: The regex used here was written by #alex here: Regex to match an IP address
If this doesn't help, then it may be a configuration issue. A few other things to check that might help with troubleshooting are:
Does gethostbyaddr('127.0.0.1'); throw the same error?
Do you have a firewall that prevents the DNS request from going through?
Can you use the dig command from the server to issue a lookup on the IP?

Get the IP address (192.168.X.X, assigned by the wireless router) in my webpage?

How do I get the inner IP address in my webpage? Can be any language for designing a website (javascript,php,etc.). What I need to do actually, is to make a local web server, and to let the clients in the same wifi network to connect via its shown IP address(192.168.X.X) on a webpage. But I always get 127.0.0.1 in php instead of 192.168.X.X, any ideas?
I solved by the following code, getting the wireless local IP address(192.168.X.X):
$myIP = gethostbyname(trim(`hostname`));
// PHP < 5.3.0
$Local_IP = #gethostbyname(php_uname('n'));
// PHP >= 5.3.0
$Local_IP = #gethostbyname(getHostName());
You just have to read it in
$ip = $_SERVER['SERVER_ADDR'];
If you want to know all data available in $_SERVER use:
print("<pre>\n");
print_r($_SERVER);
print("\n</pre>\n");
$_SERVER contains lots of useful informations. You may also want to check:
$_SERVER['LOCAL_ADDR']

Determining the hostname/IP address from the MX record in PHP

have a basic email domain validation script that takes a user's email domain, resolves the IP address from that and then checks that against various published blacklists. Here is how I am determining the IP:
$domain = substr(strchr($email, '#'), 1);
$ip = gethostbyname($domain);
The problem is that some email address domains, such as soandso#alumni.example.net, use an MX record rather than an A record, so using gethostbyname('alumni.example.net') will fail to resolve. I know when a user's email is using an MX in the email itself by using the PHP checkdnsrr function, but once at that stage am a little stuck as to how to proceed.
In theory, I could parse out the 'root' domain, i.e. 'example.net' and check it, but I've not found reliable regex that can handle this task when the user could easily have an email the format of user#corp.example.co.uk...
So, any suggestions on how to best tackle this??
Instead of using gethostbyname, use dns_get_record, something like dns_get_record($domain,DNS_MX). See the docs for how the return values are structured.
$Arr = dns_get_record('ford.com' , DNS_MX);
$count = count($Arr);
for($i=0; $i<$count; $i++) {
echo $i.'-'.$Arr[$i]['target'].'-'.gethostbyname($Arr[$i]['target']).'-'.$Arr[$i]['ttl'].'<br/>';
}
I got the result with ip address as following order(Pref, host, ip, ttl).
0-cluster4a.us.messagelabs.com-85.158.139.103-453
1-cluster4.us.messagelabs.com-216.82.242.179-453
The easiest is probably
if (!getmxrr($host, $result)) {
$result=array($host);
}
Then loop over the results, calling gethostbyname() and checking that none are blacklisted (or you could pick the result with the lowest weight, but that could be easily used to circumvent the blacklist).
I'd question the usefulness of blacklisting a destination; DNS spam blacklists are usually made for blacklisting sources.
You cannot do source validation based solely on someone's e-mail address, because (in general) any party anywhere on the internet can send any e-mail with anyone else's e-mail address in it.
Using this function you can only check atleast one mx records is available for the given domain. Code is not tested with multiple domains.
function mxrecordValidate($email){
list($user, $domain) = explode('#', $email);
$arr= dns_get_record($domain,DNS_MX);
if($arr[0]['host']==$domain&&!empty($arr[0]['target'])){
return $arr[0]['target'];
}
}
$email= 'user#radiffmail.com';
if(mxrecordValidate($email)) {
echo('This MX records exists; I will accept this email as valid.');
}
else {
echo('No MX record exists; Invalid email.');
}
If find any improvement in this function, comments are appreciated.
Try:
$result = shell_exec ('host -t MX '.$domain);
var_dump ($result);
or
exec ('host -t MX '.$domain, $result = array ());
var_dump ($result);
You will get list of MX records, you can parse it and check each record with gethostbyname().
Edit
dns_get_record() mentioned by Ycros will be better.

Categories