gethostbyaddr

(PHP 3, PHP 4, PHP 5)

gethostbyaddr --  Get the Internet host name corresponding to a given IP address

Description

string gethostbyaddr ( string ip_address )

Returns the host name of the Internet host specified by ip_address or a string containing the unmodified ip_address on failure.

例子 1. A simple gethostbyaddr() example

<?php
$hostname
= gethostbyaddr($_SERVER['REMOTE_ADDR']);
  
echo
$hostname;
?>

See also gethostbyname(), and gethostbynamel().


add a note add a note User Contributed Notes
CanYouFlyBilly
18-Apr-2006 05:08
Just wanted to contribute for the solaris folks out there that don't have "host" installed.  This will return the resolved named of the specified ip address if it exist.

NOTE: The " " in the explode statement should be a tab character. explode was used instead of preg_split in order to eliminate regular expression overhead.

<?
function gethost($ipaddress)
{
  
$host = trim( `getent hosts $ipaddress` );
  
$host=explode(" ",$host);
   if(isset(
$host[1])) return $host[1];
   else return
"";
}
?>
oryan at zareste dot com
01-Mar-2006 07:17
If all else fails, but you have shell access, Unix/Linux servers can use this for a timeout response:

shell_exec('host -W 2 0.0.0.0');

Where 0.0.0.0 is of course the IP, and '2' is the number of seconds for the timeout.  This returns a more detailed string of info, with some additional text which might vary depending on the system, so if you want a string with the hostname and nothing else, you'll have to do some substring cutting.  There should be an equivalent of 'host' for Windows users to execute, but it isn't my platform.
Rathann
27-Feb-2006 01:51
While writing a script to verify IP<->hostname loops, I sorely missed the "list" version of gethostbyaddr (similar to gethostbynamel()) and since dns_get_record is a bit too complex for that task alone, I've written a simple wrapper that should behave like gethostbynamel():

function gethostbyaddrl($ip) {
   $rrs=dns_get_record(implode('.',array_reverse(explode('.', $ip))).'.in-addr.arpa.',DNS_PTR);
   $revnames=array();
   foreach($rrs as $rr) $revnames[]=$rr['target'];
   return (count($revnames)) ? $revnames : FALSE;
}

Hopefully it'll be of use to someone else, too.
respaldod at gmail dot com
23-Nov-2005 02:28
There is a small flaw in the timeout implementation of King Macro's very useful sockets-based function gethostbyaddr_timeout() below.

The parameters for socket_set_timeout, an alias for stream_set_timeout(), are like this:
( resource stream, int seconds [, int microseconds] )

So if you want to use his parameters, and assuming the $timeout param should be in milliseconds, you could first convert to microseconds

$timeout *= 1000;

And then change the socket_set_timeout so you have seconds and microseconds along these lines:

@socket_set_timeout($handle, floor($timeout/1000000), $timeout%1000000);
tom
07-Oct-2005 04:14
Be careful with the usage of this function - it will slow down a server to a crawl if called a lot and the slowness won't be reflected in any of the obvious places, like CPU usage, apache requests, SQL etc. When you do use it make a special note of where!
reinhard at ess dot co dot at
12-Apr-2005 05:27
tried out some of the examples below, but no one worked for me.
(
"host" returns something if domain-name wasn't found
"gethostbyaddr" has a too long  timeout when it fails
"the udp-example" returns some strange characters...
)
so i have changed the "host"-example a little bit. hope someone can need it. (maybe with little changes like without error-description)

<?
function gethost($ip)
{
  
$host = `host $ip`;
  
$host=end(explode(' ',$host));
  
$host=substr($host,0,strlen($host)-2);
  
$chk=split("\(",$host);
   if(
$chk[1]) return $ip." (".$chk[1].")";
   else return
$host;
}
?>
king dot macro at gmail dot com
26-Oct-2004 10:28
The problem of broken DNS servers was causing me a problem because i had a page for user statistics that required around 20 reverse dns lookups to be done, and even as many as 5/6 of them being broken was causing a huge delay in loading the page. so i wrote a function that uses a UDP socket to talk directly to the DNS server (instead of going via the normal gethostbyaddr function) this let me set a timeout.

The only requirement is that your DNS server must be able to do recursive lookups, it wont go to other DNS servers if its told to... and of course you need to know your DNS servers IP address :-)

<?
function gethostbyaddr_timeout($ip, $dns, $timeout=1000)
{
  
// random transaction number (for routers etc to get the reply back)
  
$data = rand(0, 99);
  
// trim it to 2 bytes
  
$data = substr($data, 0, 2);
  
// request header
  
$data .= "\1\0\0\1\0\0\0\0\0\0";
  
// split IP up
  
$bits = explode(".", $ip);
  
// error checking
  
if (count($bits) != 4) return "ERROR";
  
// there is probably a better way to do this bit...
   // loop through each segment
  
for ($x=3; $x>=0; $x--)
   {
      
// needs a byte to indicate the length of each segment of the request
      
switch (strlen($bits[$x]))
       {
           case
1: // 1 byte long segment
              
$data .= "\1"; break;
           case
2: // 2 byte long segment
              
$data .= "\2"; break;
           case
3: // 3 byte long segment
              
$data .= "\3"; break;
           default:
// segment is too big, invalid IP
              
return "INVALID";
       }
      
// and the segment itself
      
$data .= $bits[$x];
   }
  
// and the final bit of the request
  
$data .= "\7in-addr\4arpa\0\0\x0C\0\1";
  
// create UDP socket
  
$handle = @fsockopen("udp://$dns", 53);
  
// send our request (and store request size so we can cheat later)
  
$requestsize=@fwrite($handle, $data);

   @
socket_set_timeout($handle, $timeout - $timeout%1000, $timeout%1000);
  
// hope we get a reply
  
$response = @fread($handle, 1000);
   @
fclose($handle);
   if (
$response == "")
       return
$ip;
  
// find the response type
  
$type = @unpack("s", substr($response, $requestsize+2));
   if (
$type[1] == 0x0C00// answer
  
{
      
// set up our variables
      
$host="";
      
$len = 0;
      
// set our pointer at the beginning of the hostname
       // uses the request size from earlier rather than work it out
      
$position=$requestsize+12;
      
// reconstruct hostname
      
do
       {
          
// get segment size
          
$len = unpack("c", substr($response, $position));
          
// null terminated string, so length 0 = finished
          
if ($len[1] == 0)
              
// return the hostname, without the trailing .
              
return substr($host, 0, strlen($host) -1);
          
// add segment to our host
          
$host .= substr($response, $position+1, $len[1]) . ".";
          
// move pointer on to the next segment
          
$position += $len[1] + 1;
       }
       while (
$len != 0);
      
// error - return the hostname we constructed (without the . on the end)
      
return $ip;
   }
   return
$ip;
}
?>

This could be expanded quite a bit and improved but it works and i've seen quite a few people trying various methods to achieve something like this so i decided to post it here. on most servers it should also be more efficient than other methods such as calling nslookup because it doesn't need to run external programs

Note: I'm more a C person than a PHP person, so just ignore it if anything hasn't been done the *recomended* way :-)
MagicalTux at FF.ST
16-Mar-2004 02:58
Note that sometime, people have broken DNS...

I mean that the IP resolve to a domain, but the reverse-resolution don't give the same IP.

I did a local test, putting a PTR record on my dns server to say 192.168.0.1 resolv to php.net . When calling gethostbyaddr, I saw "Your host is php.net" ... So when you log the DNS names, you have two options :
 - Log the IP adresses to prevent fake ips
 - Call gethostbyname on the result and verify that the IP is really the initial IP.

Note that not everyone can do that, only people with control on their own ip classes... Once, on the real net, I got an IP resolving to "PROGRAM". It was obviously a fake record.

Note 2 for windows users : I noticed that some software takes the reverse record as athoritative. It may allow people to do fake DNS entries if you do the reverse dns on your host. The best is to only log IPs. Imagine someone with an host resolving to www.paypal.com. Next time you try to access paypal, you will be redirected to his/her IP without even knowing it. Also faking update servers for antivirus software, or winamp (there was a thread regarding this security problem because of a problem in winamp updater if the remote server was faked) will be concerned.
Matt AKA Junkie
15-Mar-2004 12:29
Going through numerous tests, the following results are concluded:

<?
// If you're using a server on Windows, this is faster
function getisp($ip='') {
   if (
$ip=='') $ip = $_SERVER['REMOTE_ADDR'];
  
$longisp = @gethostbyaddr($ip);
  
$isp = explode('.', $longisp);
  
$isp = array_reverse($isp);
  
$tmp = $isp[1];
   if (
preg_match("/\<(org?|com?|net)\>/i", $tmp)) {
      
$myisp = $isp[2].'.'.$isp[1].'.'.$isp[0];
   } else {
      
$myisp = $isp[1].'.'.$isp[0];
   }
   if (
preg_match("/[0-9]{1,3}\.[0-9]{1,3}/", $myisp))
     return
'ISP lookup failed.';
   return
$myisp;
}

// If your server is on a *nix system, this is faster
function gethost ($ip) {
 
$host = `host $ip`;
 return ((
$host ? end ( explode (' ', $host)) : $ip));
}

// be warned, however, that gethost() will issue a warning
// if safe mode is on with the use of backticked variables

?>
webmaster at script-tease dot net
14-Mar-2004 08:37
gethostbyaddr() tends to lag on various systems for whatever reason. Here are two functions that should prove their worth speedwise.

<?php
// For Linux...

function gethost ($ip) {
 
$host = `host $ip`;
 return ((
$host ? end ( explode (' ', $host)) : $ip));
}

// For Win32...

function nslookup ($ip) {
 
$host = split('Name:',`nslookup $ip`);
 return (
trim (isset($host[1]) ? str_replace ("\n".'Address:  '.$ip, '', $host[1]) : $ip));
}
?>

Pretty basic, but it should get the job done.
Matt AKA Junkie
01-Mar-2004 08:11
Since my little ISP thing isn't globally acceptable, here's an update.

<?
function getisp($ip='') {
   if (
$ip=='') $ip = $_SERVER['REMOTE_ADDR'];
  
$longisp = @gethostbyaddr($ip);
  
$isp = explode('.', $longisp);
  
$isp = array_reverse($isp);
  
$tmp = $isp[1];
   if (
preg_match("/\<(org?|com?|net)\>/i", $tmp)) {
      
$myisp = $isp[2].'.'.$isp[1].'.'.$isp[0];
   } else {
      
$myisp = $isp[1].'.'.$isp[0];
   }
  
preg_match("/[0-9]{1,3}\.[0-9]{1,3}/", $myisp) ? return 'ISP lookup failed.' : return $myisp;
}
?>
info at widebore dot com
18-Aug-2003 04:49
Some users (a minority) will present IP addresses to the browser which cause problems with gethostbyaddr. I had a complaint from a user today about this.

This gives an error "Warning: Address is not in a.b.c.d form" and if you try to send any headers after this error has been generated, then, naturally, the results are unpleasant on the user's screen.

The simplest way I found to get round this problem which affects less than 1% of users is to put a "@" in front of gethostbyaddr and not lose any more sleep over it :-)
grimNOSPAMtraffic at hotNOSPAMmail dot com
01-Aug-2003 05:31
If you have found the host of the ip, the shortest way to cut it not to display the full hostname to the public would be:

$host = substr($host, strpos($host, ".") + 1);

P.S. strpos() can also be easily used if you want to put "*" for every simbol you ommit, like so:

$os = strpos($host, ".");
$host = substr($host, $os);
$host = str_repeat("*", $os) . $host;

--McTrafik
www.ad-rotator.com
29-Apr-2003 07:06
For ad-rotator.com, we need to do a lot of IP lookups, gethostbyaddr is very easy get timed-out and the script stucks there forever. Here is a fail-safe alternative, 1 sec max for timeout per IP.

function ar_gethostbyaddr($ip) {
  $output = `host -W 1 $ip`;
  if (ereg('.*pointer ([A-Za-z0-9.-]+)\..*',$output,$regs)) {
   return $regs[1];
  }
  return $ip;
}
jz at NOSPAM dot nplu dot kiev dot ua
11-Apr-2003 06:59
Just to fun that gethostbyadd() returns server machine name known in LAN rather then its DNS if I try to call it against my own host (from workstation), whether it would local (behind the proxy) or global (of proxy itself) IP or just loop 127.0.0.1.

And thus you can get LAN names of other workstations by its intranet IPs (I mean smth like 192.168.0.???)

Fun :)
kriek at jonkriek dot com
22-Mar-2003 12:39
In response to god at weaponzero dot f2s dot com: I found this much easier to write.

<?php
   $ip
= $_SERVER['REMOTE_ADDR'];
  
$fullhost = gethostbyaddr($ip);
  
$host = preg_replace("/^[^.]+./", "*.", $fullhost);
?>

IP address <?=$ip?> | Host: <?=$host?>

You can still protect the IP of your visitors and only show the hostname or show them both.
root don't send spam to em411 dot com
08-Feb-2003 02:01
recently, i've encountered a bad experience with this function. while i have yet to find out the root of the problem, i would like to share my experience.

i woke up one morning to find all pages on my server loading very slowly. frontpage load speed is typically .4seconds, and that morning, it was 12seconds. after 24 hours of myisamchk'ing, top / ping / tracert / reboot / service mysqld / httpd restartin'ing, nothing helped. eventually, i tracked the bugger down to the gethostbyaddr function.

the anomaly was that the problem was only happening to ME, and not to my 1-200 users per day.

would love to hear suggestion on why this happened and potential resolutions, if any exist. thank you.
webmaster at 4so9 dot com
26-Dec-2002 02:12
I could never get one host name from this function. I have even tried to turn on "HostnameLookup On" w/o success. I have combined all your your advises into this piece of codes. Any help on this is greatly appreciated.

------
function getRemoteInfo () {
   $proxy="";
   $IP = "";
   if (isSet($_SERVER)) {
       if (isSet($_SERVER["HTTP_X_FORWARDED_FOR"])) {
           $IP = $_SERVER["HTTP_X_FORWARDED_FOR"];
           $proxy  = $_SERVER["REMOTE_ADDR"];
       } elseif (isSet($_SERVER["HTTP_CLIENT_IP"])) {
           $IP = $_SERVER["HTTP_CLIENT_IP"];
       } else {
           $IP = $_SERVER["REMOTE_ADDR"];
       }
   } else {
       if ( getenv( 'HTTP_X_FORWARDED_FOR' ) ) {
           $IP = getenv( 'HTTP_X_FORWARDED_FOR' );
           $proxy = getenv( 'REMOTE_ADDR' );
       } elseif ( getenv( 'HTTP_CLIENT_IP' ) ) {
           $IP = getenv( 'HTTP_CLIENT_IP' );
       } else {
           $IP = getenv( 'REMOTE_ADDR' );
       }
   }
   if (strstr($IP, ',')) {
       $ips = explode(',', $IP);
       $IP = $ips[0];
   }
   $RemoteInfo[0]=$IP;
   $RemoteInfo[1]=@GetHostByAddr($IP);
   $RemoteInfo[2]=$proxy;
   return $RemoteInfo;
}

-------
Thanks,
Steve
lukevb_at_iafrica.com
09-Nov-2002 06:43
Sometimes when using $_SERVER['HTTP_X_FORWARDED_FOR'] OR $_SERVER['REMOTE_ADDR'] more than 1 IP address is returned, for example '155.240.132.261, 196.250.25.120'. When this string is passed as an argument for gethostbyaddr() PHP gives the following error: Warning: Address is not a valid IPv4 or IPv6 address in...

To work around this I use the following code to extract the first IP address from the string and discard the rest. (If you wish to use the other IPs they will be in the other elements of the $ips array).

if (strstr($remoteIP, ', ')) {
   $ips = explode(', ', $remoteIP);
   $remoteIP = $ips[0];
}

Hope this helps someone :)
abe at abe2k dot net
08-Nov-2002 10:32
gethostbyaddr() doesn't seem to be able to resolve ip6.int
(ipv6) adresses, so I made a function that can, and works
just like the normal gethostbyaddr().

You need dig and ipv6calc, dig should come with most
distributions, if not, install bind from http://www.isc.org.
ipv6calc can be found at http://www.bieringer.de/linux/IPv6/ipv6calc/index.html.

 function gethostbyaddr6($ip6) {
  $ipv6calc = "/bin/ipv6calc";
  $dig = "/usr/bin/dig";
  $file = popen($ipv6calc." --in ipv6addr --out revnibbles.int ".escapeshellarg($ip6), r);
  $ip = fread($file, 128);
  pclose($file);
  if ((substr($ip, 0, 5) == "Error") || (!$ip)) return "Address is not a valid IPv6 address";
  $file = popen($dig." ptr ".$ip, r);               
   while (!feof ($file)) {
   $buffer = fgets($file, 128);
   if (substr($buffer, 0, 1) == ";") continue;
   $buffer = explode(" ", $buffer);
   if ($buffer[3] == "PTR") {
     $host = substr(trim($buffer[4]), 0, -1);
     pclose($file);
     return $host;
   }
   }
  pclose($file);
  return $ip6;
 }

 echo gethostbyaddr6($_SERVER[REMOTE_ADDR]);
ameoba32 at mail dot ru
01-Nov-2002 08:29
DNS lookup with timeout

function dns_timeout($ip) {
 $res=`nslookup -timeout=3 -retry=1 $ip`;
 if (preg_match('/\nName:(.*)\n/', $res, $out)) {
   return trim($out[1]);
 } else {
   return $ip;
 }
}
dominique at vdx dot nl
30-Sep-2002 08:14
To convert an IP to a numeric value, just use the ip2long (...) function.

Vice versa; use: long2ip (...)
pulstar at mail dot com
21-Sep-2002 05:59
If you need to store an IP addresses in a database, you can convert and store it in an INT type column (4 bytes). The functions below can convert IP addresses to its integer decimal value and vice-versa.

function ip2dec($ipaddr) {
  $base=explode(".",$ipaddr);
  $decimal=(double) $base[0]*16777216;
  $decimal+=$base[1]*65536;
  $decimal+=$base[2]*256;
  $decimal+=$base[3];
  if($decimal>2147483647) {
   $decimal-=4294967296;
  }
  return (int) $decimal;
}

function dec2ip($dec) {
  if($dec<0) {
   $dec=(double) 4294967296+$dec;
  }
  if($dec>16777215) {
   $ip=$dec-(intval($dec/256)*256);
   $dec=(double) intval($dec/256);
  } else $ip="0";
  if($dec>65535) {
   $ip=($dec-(intval($dec/256)*256)).".".$ip;
   $dec=(double) intval($dec/256);
  } else $ip="0.".$ip;
  if($dec>255) {
   $ip=($dec-(intval($dec/256)*256)).".".$ip;
   $dec=(double) intval($dec/256);
  } else $ip="0.".$ip;
  $ip=$dec.".".$ip;
  return (string) $ip;
}
alexey at ozerov dot de
16-Sep-2002 01:15
This function seems to be very slow on IIS 4.0 Server (Win32). I use system call to NSLOOKUP instead to get PC-Hostname:

unset ($execoutput);
exec ("nslookup $IPAdresse 2>nul",$execoutput,$nslookstatus);
if (isset ($execoutput[3]) && ereg ("^Name: *([A-Za-z0-9]{2,})\.",$execoutput[3],$regs))
$nslookname=strtoupper($regs[1]);
else $nslookname="Unknown";

Note by members: This is not portable to Windows platforms. so you would be better to stay with our function.
stephane at metacites dot net
10-Sep-2002 10:17
gethostbyaddr_with_cache()

As someone truely said upper in the forum, some unresolved addresses may slow down your script to the point it times out.

Althought I had thought gethostbyaddr() would use some kind of cache, it doesn't seem to when the IP is unresolved (at least on my win machine).

So, I've coded a little gethostbyaddr_with_cache() function that will greatly speed your page if you have many gethostbyaddr() to perform on the same page.

function gethostbyaddr_with_cache($a) {
  global $dns_cache;
  if ($dns_cache[$a]) {
   return $dns_cache[$a];
   } else {
   $temp = gethostbyaddr($a);
   $dns_cache[$a] = $temp;
   return $temp;
  }
   }
inny at core dot fetchnet dot org
11-Aug-2002 12:58
Turning on the HostnameLookup function on in the apache configuration file will severely increase the loading times of all the pages serviced by the httpd-server.
It's mostly a better idea to just use gethostbyaddr($REMOTE_ADDR); instead of $REMOTE_HOST if you turned HostnameLookups On, unless you want the hostnames specified in apache's log file...
ven at PragaKhan dot com
16-Jul-2002 06:55
$REMOTE_HOST or $_SERVER['REMOTE_HOST'] will give you the reversed ip IF apache is setup to do hostname lookups.

HostnameLookups On
elpmille at indiana dot edu
30-May-2002 03:26
I previously used something very similar to what god@weaponzero.f2s.com posted but found it to be quite tedious for getting the 'nicehost'. This method below is a lot cleaner, and it also works for numeric addresses.

function nicehost($host) {
   if (ereg('^([0-9]{1,3}\.){3}[0-9]{1,3}$', $host)) {
       return(ereg_replace('\.[0-9]{1,3}$', '.*', $host));
   } else {
       return(ereg_replace('^.{' . strpos($host, '.') . '}', '*', $host));
   }
}
nothanks at nospam dot com
17-May-2002 06:30
This is also very useful if you'd like to ban these annoying people that keep spamming your forums. It requires a clever use of mySql but can be great:

First, make a table for the bans, then make the query:

"SELECT banReason from tBans where '". gethostbyaddr($REMOTE_ADDR) ."' LIKE banMask"

If your results aren't null it means his host matched a banMask in your DB, so you can redirect him with header() to a banned.php page and prevent him from accessing any content on your page!
phalkon at nospam dot home dot com
09-Jun-2001 06:58
Be cautious when looking up many hostnames.  If your DNS server is slow to respond, you may have to pump up your Max execution time for your scripts, otherwise, it will timeout.  I found that even 3 unresolvable hosts can cause a 30 second delay in processing.
god at weaponzero dot f2s dot com
13-May-2001 08:53
say you want to protect the IP of your visitors and only show the hostname?


  $ip = getenv('REMOTE_HOST');
  $host = @GetHostByAddr($ip);

     $real_host=chop($host);
     if($real_host){
       $host_arr=explode(".", $real_host);
       $count=count($host_arr);
       if($count > 1){
         if(intval($host_arr[$count-1])!=0){
           $host=substr($real_host,0,strrpos($real_host,".")).".*";
         }
         else{
           $host = "*".strstr($real_host, ".");
         }
       }
       else{
         $host=$real_host;
       }
     }
     else{
       $host="";
     }


for me that would put *.dab.bellsouth.net and for AOLers it woud put *.proxy.aol.com
andy at occ dot nu
12-Jan-2001 10:48
if the user is sitting behind a proxy server, you can do this;

<?
  
if ($HTTP_SERVER_VARS["HTTP_X_FORWARDED_FOR"] != ""){
      
$IP = $HTTP_SERVER_VARS["HTTP_X_FORWARDED_FOR"];
      
$proxy = $HTTP_SERVER_VARS["REMOTE_ADDR"];
      
$host = @gethostbyaddr($HTTP_SERVER_VARS["HTTP_X_FORWARDED_FOR"]);
   }else{
      
$IP = $HTTP_SERVER_VARS["REMOTE_ADDR"];
      
$host = @gethostbyaddr($HTTP_SERVER_VARS["REMOTE_ADDR"]);
   }
?>

ps; i use $HTTP_SERVER_VARS["something"] instead of just $something;
you can get most of the $HTTP_SERVER_VARS by just using there $something equivalent, see the manual for that (preserved variables)
bruno at angelsp dot org
23-Nov-2000 10:20
This is a really usefull function.. I ussualy use it to know the name of the country that the host has.. (.pt, .es, .uk, etc)..

here is a litle idea of what one can do with this..

I get the $ipa with the remote_addr function..

<?php

  $host
gethostbyaddr($ipa);

 
$at        = $host
  $hostdot 
= ".";
 
$result    = strrchr($at, $hostdot);

  echo
"The country is $result";


?>


Of course, if a .com or .org or .net domain name (tld) it won't be a country.. but you can work that out with and if or case statements..

and of course, I can be totally mistaken ;P
php3 at bigsky dot net
16-Mar-2000 08:34
To check a host's address:
<pre>
$r_hostname = gethostbyaddr($REMOTE_ADDR);
if ($REMOTE_ADDR == "$r_hostname") {
     ....
}
</pre>

This will fail if  a lookup on the name returns the IP as the domain name (which can happen if you control a DNS server), but it's a pretty contrived example, and in any other case it will work.