Using PHP classes to navigate distributed whois databases - Looking at the pieces (
Page 5 of 7 )
main.whois
The base class is class "Whois" defined in main.whois. We've intentionally
upper-cased the "W" which means that if can begin working with this in
your existing scripts, the new class will not collide with anything that
may be using the old version 1 whois.php3.
The $Query variable is a hash that functions more or less as the local
environment for the object. It keeps track of things like what our
current whois server is ($Query["server"]), what the current TLD is
($Query["tld"], not as obvious as you might think at first glance,
considering the nominet uk.com and gb.net, which we support),
what the actual query is ($Query["string"]) and last but definately
not least, an array of any errors encountered in $Query["errstr"].
We invoke the class in the normal method, and pass our query as well:
$whois = new Whois("devshed.com");
In PHP we can create constructors for our classes by putting a function
in the class with the same name as the class. We rely heavily on those
here and in our first constructor we basically get everything ready
for a normal domain lookup (we don't have to invoke the class this way
but for our purposes we'll just look at domain lookups in normal fashion
for now).
class Whois {
..
..
..
function Whois ($query="") {
require("servers.whois");
$this->VERSION=sprintf("Whois2.php v%s:%s", $this->CODE_VERSION,
$this->DATA_VERSION);
if(isSet($query)) {
$this->Query["string"]=strtolower($query);
$tld=$this->GetTld($this->Query["string"]);
if($tld) {
$this->Query["server"]=$this->DATA[$tld][0];
if(isSet($this->DATA[$tld][1])) {
$handler=$this->DATA[$tld][1];
$this->Query["file"]=sprintf("%s.whois",$handler);
$this->Query["handler"]=$handler;
}
$this->Query["tld"]=$tld;
} else {
$this->Query["status"]=-1;
$this->Query["errstr"][]=$this->Query["string"].
" domain is not supported";
unset($this->Query["server"]);
}
} else {
$this->Query["server"]=$this->NSI_REGISTRY;
}
}
So we set the TLD, set the current whois server, and if we have one,
we define an extended handler. The whois.main then takes care of the
basic tasks that we need to do regardless of what we're doing it to:
connect to the server with Connect(), send the query string and read
back the output with Lookup(), and then, if we have an extended handler,
pass the result to Process().
servers.whois
One of the first orders of business to to load the "servers.whois" file.
This contains the $DATA array which is an array indexed by supported
TLD's, the values of which are arrays with their corresponding whois
server as their first value, and an optional "extended handler" as
value 2. We want to keep all this in a seperate file because this
data will take on an update history seperate from the code itself,
as new whois servers are reported and (hopfully) energetic PHP coders
provide additional extended classes for various TLDs and registrars.
extended handlers
The extended handlers demonstrate PHP extended classes and inheritance.
Because output varies wildy from server to server, we provide additional
processing of raw output via modular and extensible "handlers", which
in themselves, can utilize even further handlers.
Take "devshed.com" as our example again. We know from using the information
in the $DATA array that it will be queried at whois.nsiregistry.net, the
central registry server. We also see that there is an extended handler
"gtld" specified for this TLD. So the Process() function is going to
load the code in gtld.whois and then invoke an instance of the gtld
class which extends the whois class.
if(!defined("__GTLD_HANDLER__")) define("__GTLD_HANDLER__",1);
class gtld extends Whois {
var $HANDLER_VERSION = "1.0";
..
..
function gTLD ($data,$query) {
$this->Query=$query;
$this->SUBVERSION = sprintf("%s-%s", $query["handler"],
$this->HANDLER_VERSION);
$this->result["regyinfo"]=$this->ParseRegInfo($data["rawdata"]);
if($this->HACKS["nsi_referral_loop"] &&
$this->result["regyinfo"]["whois"]==
$this->HACKS["wrong_netsol_whois"] ) {
$this->Query["server"]=$this->HACKS["real_netsol_whois"];
} else {
$this->Query["server"]=$this->result["regyinfo"]["whois"];
}
$this->result["rawdata"]=$this->Lookup($this->Query["string"]);
$this->Query["handler"] =
$this->REGISTRARS[$this->result["regyinfo"]["registrar"]];
if(!empty($this->Query["handler"])) {
$this->Query["file"]=sprintf("%s.whois", $this->Query["handler"]);
$this->result["regrinfo"]=$this->Process($this->result["rawdata"]);
}
}
Once again there is a class constructor in class gltd, and we parse the
registry output in to key/value pairs. It also turns out that the registrar
for devshed.com happens to be Network Solutions, and as it so happens, we
have yet another extended class "netsol" so we query that server, get the
results, and and hand it off to class "netsol" parse it into key/value
pairs as well.
The gtld object uses it's inherited Process() and Lookup() methods to
do the follow-up query to the appropriate whois server, and if that's
it, it would stop there, returning the raw output. But in this case
the gtld class does have a "netsol" handler to further process
the data, so it hands off to it for parsing.
We can then add further handlers for ICANN accredited registrars by adding
them $REGISTRARS array of the gtld, much in the fashion we can add additional
ccTLD handlers to the $DATA array.