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!

{mospagebreak title=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.

{mospagebreak title=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.

{mospagebreak title=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.  Meet you in the next article! 

[gp-comments width="770" linklove="off" ]

chat