In this article you will learn how to use some
useful PHP networking functions that will help you perform a variety of
common networking tasks. To that end, you will build a simple
networking query application in PHP 5.
Build a Query Processor Class for Networking in PHP 5
Welcome
to the first of three tutorials in a series that covers network
programming in PHP. In this article you will learn how to use some
useful PHP networking functions that will help you perform a variety of
common networking tasks. To that end, you will build a simple
networking query application in PHP 5.
Introduction
For many PHP developers, network programming seems to be rather elusive terrain. It
becomes even more difficult to navigate when dealing with advanced
topics, such as working with low-level sockets or dealing with the
numerous and intimidating features of a specific network protocol.
However,
things aren't as hard as they look at first glance. As with everything
in software development (and particularly when developing
Internet-related applications), it's possible to dive into the network
programming area in a friendly way, without the need to get completely
obfuscated by the buzzwords that surround the topic, or without
suffering premature aging, all because you can't get that socket opened
on a particular TCP port.
Now, and seriously speaking, when you
start using PHP to develop your Web applications, sooner or later
you'll be faced with solving some specific issues related to network
programming. Actually, this makes a lot of sense, considering the fact
that the Web is a big part (and certainly the most friendly one) of the
Internet, which is after all a giant network.
For this reason,
and others that you may want to add from your own experience, this
series will be focused exclusively on building a simple -- yet useful
-- networking query application in PHP 5. It will expose some useful
methods, handy for performing a few common networking tasks, such as
converting host names to their IP addresses and vice versa, searching
for DNS records, scanning TCP ports, finding the port number of a given
service, and more.
The networking query application that I plan
to build will be encapsulated within a single PHP 5 class, but you can
easily modify its complete source code in order to work with PHP 4. As
I said before, this application should be considered a practical
introduction to using many PHP built-in functions included in the
corresponding PHP network library, so if you want to learn how to use
these functions, this series might help you to start quickly including
them in your own applications.
Now, with the preliminaries out of our way, it's time to start coding the network query class. Let's do it together!
Build a Query Processor Class for Networking in PHP 5 - Building the class: Converting host names to IP addresses and vice versa
A good place to start coding the PHP 5 class that implements my networking query application is naturally
with defining its constructor method, which takes up just one incoming
parameter for doing its business: the name of the Internet host being
queried.
Since this is merely my first attempt at coding the
class, for the moment this host name will be passed, for instance, in
the form "hostname.com" or "hostname.net" or whatever you want to pass
as host name to the class, without checking whether or not the host
exists.
Keeping in mind the initial condition that I mentioned
above, the skeleton of the PHP 5 class, which not surprisingly I named
"QueryProcessor," can be defined as follows:
class QueryProcessor{
private $host;
public function __construct($host='myhost.com'){
$this->host=$host;
}
}
As
shown by the above snippet of code, the "QueryProcessor" class has only
one method (this is only temporary), that is its constructor, which
accepts as a unique parameter the name of the Internet host being
queried. In this case I also decided to assign a default value for the
corresponding host name (myhost.com), but obviously you should change
this value and provide another host name.
Right, now that you saw
how the primitive structure of the above class looks, it's time to
provide the class with the ability to do something more useful than
assigning the respective host name as a class property. For this
reason, what I'll do next is add a couple of methods to the class,
which come in handy for converting the specified host name to its
corresponding IP address, and eventually for getting the complete list
of IP addresses that match the given host name.
Here are the signatures for these two new methods:
// get IP address
public function getIp(){
if(!$ip=gethostbyname($this->host)){
throw new Exception('Error converting hostname to IP
address.');
}
return $ip;
}
// get list of IP addresses
public function getIpList(){
if(!$ips=implode(' - ',gethostbynamel($this->host))){
throw new Exception('Error getting list of IP addresses
for the provided hostname.');
}
return $ips;
}
As
shown above, these two new methods, that is "getIp()" and "getIpList()"
respectively, can be used to convert the specified host name to its IP
address. In case you want to go one step further, they can also be used
to obtain the entire set of IP addresses that correspond to that host.
With
regard to the first method, I used the "gethostbyname()" PHP built-in
function, which gets the IP address corresponding to the specified
Internet host name. If the IP address can't be obtained for some
reason, this function will return the same string that was passed as
host name.
Now, if you turn your attention to the second method,
you'll see that I used another useful PHP function, "gethostbynamel(),"
in order to obtain the entire list of IP addresses that match the given
host. Since this function returns the respective IP addresses as an
array, I made the "getIpList()" method return a string containing all
the IP addresses, separated by a "-" character. Just in case the host
name can't be resolved to a list of IP addresses, the method will throw
an exception.
At this point, I provided the class with the
capacity to turn a given host name into a single IP address, or
eventually a list of them. Thus, this conversion process wouldn't be
complete if I don't include an opposite method, that is one that
converts an IP address to an Internet host name.
For the sake of
completeness, below I listed the "getHost()" method, which is
responsible for reversing the process and getting the IP address that
corresponds to a specified Internet host name:
// get host name
public function getHost(){
if(!$host=gethostbyaddr($this->getIp())){
throw new Exception('Error resolving host name.');
}
return $host;
}
As
illustrated above, the "getHost()" method uses the "gethostbyaddr()"
PHP built-in function, in order to obtain the IP address corresponding
to a given Internet host. Also, notice that I internally utilized the
public "getIp()" method for getting the IP address in question and then
passing it to the function.
However, it seems that the above
method is really redundant, because the respective host name has
already been passed in as an argument to the constructor. Well, the
reason for including this method rests mainly in the functionality of
the class, since you may want to modify its code and redefine this
method, in order to take up any well-formed IP address and convert it
to its host name.
Additionally, there's another interesting thing
that you can experiment with when using this method: if you're passing
to it the same IP address, over and over again, and you get different
host names at times, these results may be a consequence of dealing with
a host that shares multiple domains.
At this point, I defined
three methods that convert a specific host name to its corresponding IP
addresses and vice versa. So now, take a look at the definition of the
improved "QueryProcessor" class:
class QueryProcessor{
private $host;
public function __construct($host='myhost.com'){
$this->host=$host;
}
// get IP address
public function getIp(){
if(!$ip=gethostbyname($this->host)){
throw new Exception('Error resolving host IP
address.');
}
return $ip;
}
// get list of IP addresses
public function getIpList(){
if(!$ips=implode(' - ',gethostbynamel($this->host))){
throw new Exception('Error getting list of IP
addresses for the provided hostname.');
}
return $ips;
}
// get host name
public function getHost(){
if(!$host=gethostbyaddr($this->getIp())){
throw new Exception('Error resolving host name.');
}
return $host;
}
}
Okay,
at this stage the "QueryProcessor" class is now capable of performing
some useful tasks, which implies using a few networking PHP functions.
Nevertheless, there's a long way ahead of us, so it's time to jump into
the next section and continue adding more methods to the class.
Want to learn how this will be done? Please click on the link below and keep reading.
Build a Query
Processor Class for Networking in PHP 5 - Handling Internet services:
defining the "getServiceNames()" and "getServicePorts()" methods
As
I mentioned before, due to the extensible nature of the
"QueryProcessor" class, the next thing that I'll do is add to it a pair
of handy methods, aimed at handling the data associated with Internet
services and their TCP ports.
Bearing in mind this concept, the
first method, "getServicePorts()", takes an array of predefined
Internet services and returns the corresponding TCP port numbers. Its
signature is as follows:
// get TCP ports of Internet services
public function getServicePorts(){
$output='Retrieving services ports...Please wait.<br />';
foreach($this->services as $service){
if(!$port=getservbyname($service,'tcp')){
$output.='Error retrieving port of service
'.$service.'<br />';
}
else{
$output.='Service '.$service. ' runs on TCP port :'.
$port.'<br />';
}
}
return $output;
}
The
method listed above shows how to obtain the respective TCP port number
of a given Internet service by using the "getservbyname()" PHP built-in function. In this particular case, I decided to display an
error message if the TCP port can't be retrieved for some reason, but
this condition can be modified and throw an exception instead.
Also,
notice that each Internet service is obtained from the
$this->services class property, which means that additionally some
of the most common services will be stored as an array inside the
constructor. You'll see this when I list the full source code of the
"QueryProcessor" class.
Now that I've explained how the previous
method works, take a look at the next one, called "getServiceNames(),"
which takes an array of TCP ports and returns the corresponding service
name, when applicable. The signature of this new method is shown below:
// get Services by TCP ports
public function getServiceNames(){
$output='Retrieving services names...Please wait.<br />';
foreach($this->ports as $port){
if(!$service=getservbyport($port,'tcp')){
$output.='Error retrieving service name on port
'.$port.'<br />';
}
else{
$output.='TCP Port '.$port. ' is used by service :'.
$service.'<br />';
}
}
return $output;
}
As
you can see, the above method can be considered the counterpart of the
previous one, since it takes a specified TCP port and attempts to
retrieve the service that runs on that port. To perform this conversion
process, the method uses internally the "getservbyport()" PHP function,
which precisely returns (when possible) the Internet service that
corresponds to a given TCP port. Also, you must notice that all the TCP
ports are obtained from the $this->ports array, therefore this
condition means that TCP ports are assigned as a class property inside
the respective constructor.
At this stage, I added a couple of
handy methods to the "QueryProcessor" class, in order to extend its
basic functionality. Now, it's time to show its full source
code. Therefore, read the next section, in order to get the complete
class code.
Build a Query
Processor Class for Networking in PHP 5 - Assembling the methods:
listing the full source code of the "QueryProcessor" class
As
I promised before, here is the entire code for the "QueryProcessor"
class, after including the additional methods that you saw before:
class QueryProcessor{
private $host;
private
$services=array('http','https','ftp','telnet','imap','smtp','nicname',
'gopher','finger','pop3','www');
private $ports=array(21,23,25,43,70,79,80,110,143,443);
public function __construct($host='myhost.com'){
$this->host=$host;
}
// get IP address
public function getIp(){
if(!$ip=gethostbyname($this->host)){
throw new Exception('Error resolving host IP
address.');
}
return $ip;
}
// get list of IP addresses
public function getIpList(){
if(!$ips=implode(' - ',gethostbynamel($this->host))){
throw new Exception('Error getting list of IP
addresses for the provided hostname.');
}
return $ips;
}
// get host name
public function getHost(){
if(!$host=gethostbyaddr($this->getIp())){
throw new Exception('Error resolving host name.');
}
return $host;
}
// get TCP ports of Internet services
public function getServicePorts(){
$output='Retrieving services ports...Please wait.<br />';
foreach($this->services as $service){
if(!$port=getservbyname($service,'tcp')){
$output.='Error retrieving port of service
'.$service.'<br />';
}
else{
$output.='Service '.$service. ' runs on TCP
port :'. $port.'<br />';
}
}
return $output;
}
// get Services by TCP ports
public function getServiceNames(){
$output='Retrieving services names...Please wait.<br />';
foreach($this->ports as $port){
if(!$service=getservbyport($port,'tcp')){
$output.='Error retrieving service name on port
'.$port.'<br />';
}
else{
$output.='TCP Port '.$port. ' is used by
service :'. $service.'<br />';
}
}
return $output;
}
}
Now that you know how the whole "QueryProcessor" class looks, here is an example that shows how to use its methods:
try{
// instantiate 'QueryProcessor' object
$queryProc=new QueryProcessor('hotmail.com');
// display host IP address
//echo $queryProc->getIp(); // displays 64.4.32.7
// display host name
//echo $queryProc->getHost(); // displays 'hotmail.com.br'
// display IP list
//echo $queryProc->getIpList(); // displays 64.4.32.7 -
64.4.33.7
// display services ports
echo $queryProc->getServicePorts();
/* displays the following list
Retrieving services ports...Please wait.
Service http runs on TCP port :80
Service https runs on TCP port :443
Service ftp runs on TCP port :21
Service telnet runs on TCP port :23
Service imap runs on TCP port :143
Service smtp runs on TCP port :25
Service nicname runs on TCP port :43
Service gopher runs on TCP port :70
Service finger runs on TCP port :79
Service pop3 runs on TCP port :110
Service www runs on TCP port :80
*/
// display service names
echo $queryProc->getServiceNames();
/* displays the following list
Retrieving services names...Please wait.
TCP Port 21 is used by service :ftp
TCP Port 23 is used by service :telnet
TCP Port 25 is used by service :smtp
TCP Port 43 is used by service :nicname
TCP Port 70 is used by service :gopher
TCP Port 79 is used by service :finger
TCP Port 80 is used by service :http
TCP Port 110 is used by service :pop3
TCP Port 143 is used by service :imap
TCP Port 443 is used by service :https
*/
}
catch(Exception $e){
echo $e->getMessage();
exit();
}
Final thoughts
In
this first tutorial of the series, you learned how to use some useful
PHP networking functions, which were encapsulated within a PHP 5 class,
in order to perform some common networking tasks, such as converting
host names to the corresponding IP addresses and vice versa, listing
Internet service names and TCP port numbers.
Nevertheless, I'm
just scratching the surface of the PHP networking library. That's why
in the next article I'll continue adding more methods to the
"QueryProcessor" class, which will surely be quite interesting to you.
|