fix image text
[pear] / Net / Whois.php
1 <?php
2 /**
3  * Whois.php
4  *
5  * PHP Version 4 and 5
6  *
7  * Copyright (c) 1997-2003 The PHP Group
8  * Portions Copyright (c) 1980, 1993 The Regents of the University of
9  *   California.  All rights reserved.
10  *
11  * This source file is subject to version 3.01 of the PHP license,
12  * that is bundled with this package in the file LICENSE, and is
13  * available at through the world-wide-web at
14  * http://www.php.net/license/3_01.txt.
15  * If you did not receive a copy of the PHP license and are unable to
16  * obtain it through the world-wide-web, please send a note to
17  * license@php.net so we can mail you a copy immediately.
18  *
19  * @category  Net
20  * @package   Net_Whois
21  * @author    Seamus Venasse <seamus.venasse@polaris.ca>
22  * @copyright 1997-2003 The PHP Group
23  * @copyright 1980-1993 The Regents of the University of California (Portions)
24  * @license   http://www.php.net/license/3_01.txt PHP 3.01
25  * @version   CVS: $Id: Whois.php 314693 2011-08-10 00:31:45Z kguest $
26  * @link      http://pear.php.net/package/Net_Whois
27  */
28
29 require_once 'PEAR.php';
30
31 /**
32  * Looks up records in the databases maintained by several Network Information
33  * Centres (NICs).  This class uses PEAR's Net_Socket:: class.
34  *
35  * @category Net
36  * @package  Net_Whois
37  * @author   Seamus Venasse <seamus.venasse@polaris.ca>
38  * @license  http://www.php.net/license/3_01.txt PHP 3.01
39  * @link     http://pear.php.net/package/Net_Whois
40  */
41 class Net_Whois extends PEAR
42 {
43
44     // {{{ properties
45
46     /**
47      * Retrieve authoritative definition only
48      *
49      * @var boolean
50      * @access public
51      */
52     var $authoritative = false;
53
54     /**
55      * Port for whois servers
56      *
57      * @var int
58      * @access public
59      */
60     var $port = 43;
61
62     /**
63      * See options for stream_context_create.
64      *
65      * @param array
66      * @access public
67      */
68     var $options = null;
69
70     /**
71      * List of NICs to query
72      *
73      * @var array
74      * @access private
75      */
76     var $_nicServers = array (
77         'NICHOST'           => 'whois.crsnic.net.',
78         'INICHOST'          => 'whois.networksolutions.com.',
79         'GNICHOST'          => 'whois.nic.gov.',
80         'ANICHOST'          => 'whois.arin.net.',
81         'RNICHOST'          => 'whois.ripe.net.',
82         'PNICHOST'          => 'whois.apnic.net.',
83         'RUNICHOST'         => 'whois.ripn.net.',
84         'MNICHOST'          => 'whois.ra.net.',
85         'QNICHOST_TAIL'     => '.whois-servers.net.',
86         'SNICHOST'          => 'whois.6bone.net.',
87         'BNICHOST'          => 'whois.registro.br.'
88     );
89
90     /**
91      * Search string of server to search on
92      *
93      * @var string
94      * @access private
95      */
96     var $_whoisServerID = 'Whois Server: ';
97
98     /**
99      * Server to search for IP address lookups
100      *
101      * @var array
102      * @access private
103      */
104     var $_ipNicServers = array ('RNICHOST', 'PNICHOST', 'BNICHOST');
105
106     /**
107      * List of error codes and text
108      *
109      * @var array
110      * @access private
111      */
112     var $_errorCodes = array (
113         010 => 'Unable to create a socket object',
114         011 => 'Unable to open socket',
115         012 => 'Write to socket failed',
116         013 => 'Read from socket failed',
117         014 => 'Specified server is null or empty',
118     );
119
120     /**
121      * Number of seconds to wait on socket connections before assuming
122      * there's no more data from the Whois server. Defaults to no timeout.
123      * @var integer $timeout
124      * @access private
125      */
126     var $_timeout = false;
127     // }}}
128
129     // {{{ constructor
130     /**
131      * Constructs a new Net_Whois object
132      *
133      * @access public
134      */
135     function __construct($error_class = null)
136     {
137         parent::__construct();
138
139         $this->setPort();
140         $this->setAuthoritative();
141         $this->setTimeout();
142     }
143     
144     // }}}
145
146     // {{{ setTimeout()
147     /**
148      * Set timeout value - number of seconds afterwhich an attempt to connect
149      * to a whois server should be aborted.
150      *
151      * @param integer $timeout false is also an acceptable value
152      *
153      * @access public
154      * @return void
155      */
156     function setTimeout($timeout = false)
157     {
158         $this->_timeout = $timeout;
159     }
160     // }}}
161
162     // {{{ getTimeout()
163     /**
164      * Retrieve timeout value
165      *
166      * @access public
167      *
168      * @return mixed either false or an integer value
169      */
170     function getTimeout()
171     {
172         return $this->_timeout;
173     }
174     // }}}
175
176     // {{{ setTimeout()
177     /**
178      * setAuthoritative
179      *
180      * @param bool $authoritative defaults to false
181      *
182      * @access public
183      * @return void
184      */
185     function setAuthoritative($authoritative = false)
186     {
187         $this->authoritative = $authoritative;
188     }
189     // }}}
190
191     // {{{ getAuthoritative()
192     /**
193      * getAuthoritative
194      *
195      * @return bool Query for authoritative result?
196      */
197     function getAuthoritative()
198     {
199         return (bool) $this->authoritative;
200     }
201     // }}}
202
203
204     /**
205      * set which port should be used
206      *
207      * @param integer $port Port to use
208      *
209      * @access public
210      * @return void
211      */
212     function setPort($port = false)
213     {
214         $port = is_numeric($port) ? $port : getservbyname('whois', 'tcp');
215         $this->port = $port ? $port : 43;
216     }
217     // }}}
218
219     // {{{ getPort()
220     /**
221      * Retrieve which port to connect to.
222      *
223      * @return integer port to connect to
224      */
225     function getPort()
226     {
227         return $this->port;
228     }
229     // }}}
230
231     /**
232      * setOptions
233      *
234      * @param mixed $options
235      * @return void
236      */
237     function setOptions($options)
238     {
239         if ((!is_null($options)) && (!is_array($options))) {
240             return;
241         }
242         $this->options = $options;
243     }
244
245     // {{{ getOptions()
246     /**
247      * Retrieve which port to connect to.
248      *
249      * @return array
250      */
251     function getOptions()
252     {
253         return $this->options;
254     }
255     // }}}
256
257     // {{{ query()
258     /**
259      * Connect to the necessary servers to perform a domain whois query.  Prefix
260      * queries with a "!" to lookup information in InterNIC handle database.
261      * Add a "-arin" suffix to queries to lookup information in ARIN handle
262      * database.
263      *
264      * @param string $domain          IP address or host name
265      * @param string $userWhoisServer server to query (optional)
266      *
267      * @access public
268      * @return mixed returns a PEAR_Error on failure, or a string on success
269      */
270     function query($domain, $userWhoisServer = null)
271     {
272         $domain = trim($domain);
273
274         if (isset($userWhoisServer)) {
275             $whoisServer = $userWhoisServer;
276         } elseif (preg_match('/^!.*/', $domain)) {
277             $whoisServer = $this->_nicServers['INICHOST'];
278         } elseif (preg_match('/.*?-arin/i', $domain)) {
279             $whoisServer = $this->_nicServers['ANICHOST'];
280         } else {
281             $whoisServer = $this->_chooseServer($domain);
282         }
283
284         $_domain = $this->authoritative ? 'domain ' . $domain : $domain;
285         $whoisData = $this->_connect($whoisServer, $_domain);
286
287         if (PEAR::isError($whoisData)) {
288             return $whoisData;
289         }
290
291         if ($this->authoritative) {
292             $pattern = '/\s+' . preg_quote($this->_whoisServerID) . '(.+?)\n/i';
293
294             if (preg_match($pattern, $whoisData, $matches)) {
295                 $whoisData = $this->_connect(trim(array_pop($matches)), $domain);
296             }
297         }
298         return $whoisData;
299     }
300     // }}}
301
302     // {{{ queryAPNIC()
303     /**
304      * Use the Asia/Pacific Network Information Center (APNIC) database.
305      * It contains network numbers used in East Asia, Australia, New
306      * Zealand, and the Pacific islands.
307      *
308      * @param string $domain IP address or host name
309      *
310      * @access public
311      * @return mixed returns a PEAR_Error on failure, or a string on success
312      */
313     function queryAPNIC($domain)
314     {
315         return $this->query($domain, $this->_nicServers['PNICHOST']);
316     }
317     // }}}
318
319     // {{{ queryIPv6()
320     /**
321      * Use the IPv6 Resource Center (6bone) database.  It contains network
322      * names and addresses for the IPv6 network.
323      *
324      * @param string $domain IP address or host name
325      *
326      * @access public
327      * @return mixed returns a PEAR_Error on failure, or a string on success
328      */
329     function queryIPv6($domain)
330     {
331         return $this->query($domain, $this->_nicServers['SNICHOST']);
332     }
333     // }}}
334
335     // {{{ queryRADB()
336     /**
337      * Use the Route Arbiter Database (RADB) database.  It contains
338      * route policy specifications for a large number of operators'
339      * networks.
340      *
341      * @param string $ipAddress IP address
342      *
343      * @access public
344      * @return mixed returns a PEAR_Error on failure, or a string on success
345      */
346     function queryRADB($ipAddress)
347     {
348         return $this->query($ipAddress, $this->_nicServers['MNICHOST']);
349     }
350     // }}}
351
352     // {{{ _chooseServer()
353     /**
354      * Determines the correct server to connect to based upon the domain
355      *
356      * @param string $query IP address or host name
357      *
358      * @access private
359      * @return string whois server host name
360      */
361     function _chooseServer($query)
362     {
363         if (!strpos($query, '.')) {
364             return $this->_nicServers['NICHOST'];
365         }
366
367         $TLD = substr($query, strrpos($query, '.') + 1);
368
369         if (is_numeric($TLD)) {
370             $whoisServer = $this->_nicServers['ANICHOST'];
371         } else {
372             $whoisServer = $this->getDomainServer($query);
373         }
374
375         return $whoisServer;
376     }
377     // }}}
378
379     // {{{ getDomainServer()
380     /**
381      * Determines the correct whois server to connect to based upon the domain
382      *
383      * @param string $q domain name
384      *
385      * @access public
386      * @return string whois server ip address
387      */
388     function getDomainServer($q)
389     {
390         $tail = $this->_nicServers['QNICHOST_TAIL'];
391         if (strchr($q, '.')) {
392             //get the last 2 parts
393             $q = array_reverse(explode('.', $q));
394             $a = array($q[1] . '.' . $q[0], $q[0]);
395         } else {
396             $a = array($q);
397         }
398         foreach ($a as $q) {
399             //check host has real ip
400             $q = gethostbyname($q . $tail);
401             if (filter_var($q, FILTER_VALIDATE_IP)) {
402                 return $q;
403             }
404         }
405     }
406     // }}}
407
408     // {{{ _connect()
409     /**
410      * Connects to the whois server and retrieves domain information
411      *
412      * @param string $nicServer FQDN of whois server to query
413      * @param string $domain    Domain name to query
414      *
415      * @access private
416      * @return mixed returns a PEAR_Error on failure, string of whois data on success
417      */
418     function _connect($nicServer, $domain)
419     {
420         include_once 'Net/Socket.php';
421
422         if (is_null($nicServer) || (empty($nicServer))) {
423             return new PEAR_Error($this->_errorCodes[014], 14);
424         }
425
426         if (PEAR::isError($socket = new Net_Socket())) {
427             return new PEAR_Error($this->_errorCodes[010], 10);
428         }
429
430         $result = $socket->connect(
431             $nicServer,
432             $this->getPort(),
433             null,
434             $this->getTimeout(),
435             $this->getOptions()
436         );
437         if (PEAR::isError($result)) {
438             return new PEAR_Error($this->_errorCodes[011], 11);
439         }
440         $socket->setBlocking(false);
441         // Querying denic.de requires some special coaxing for a domain query.
442         // http://www.denic.de/en/faq-single/2978/1115.html
443         if (substr($domain, -3) == '.de') {
444             if (PEAR::isError($socket->writeLine("-T dn,ace " . $domain))) {
445                 return new PEAR_Error($this->_errorCodes[012], 12);
446             }
447         } else {
448
449             if (PEAR::isError($socket->writeLine($domain))) {
450                 return new PEAR_Error($this->_errorCodes[012], 12);
451             }
452         }
453
454         $nHost = null;
455
456         $whoisData = $socket->readAll();
457         if (PEAR::isError($whoisData)) {
458             return new PEAR_Error($this->_errorCodes[013], 13);
459         }
460
461         $data = explode("\n", $whoisData);
462         foreach ($data as $line) {
463             $line = rtrim($line);
464
465             // check for whois server redirection
466             if (!isset($nHost)) {
467                 $pattern='/'.$this->_whoisServerID.'([a-z0-9.]+)\n/i';
468                 if (preg_match($pattern, $line, $matches)) {
469                     $nHost = $matches[1];
470                 } elseif ($nicServer == $this->_nicServers['ANICHOST']) {
471                     foreach ($this->_ipNicServers as $ipNicServer) {
472                         $server = trim($this->_nicServers[$ipNicServer], '.');
473                         if (strstr($line, $server)) {
474                             $nHost = $this->_nicServers[$ipNicServer];
475                         }
476                     }
477                 }
478             }
479         }
480
481         // this should fail, but we'll call it anyway and ignore the error
482         $socket->disconnect();
483
484         if ($nHost && $nHost != $nicServer) {
485             $tmpBuffer = $this->_connect($nHost, $domain);
486             if (PEAR::isError($tmpBuffer)) {
487                 return $tmpBuffer;
488             }
489             $whoisData .= $tmpBuffer;
490         }
491
492         return $whoisData;
493     }
494     // }}}
495 }
496 ?>