Introduction
While building web applications, it’s often important to keep an eye on the other services running on your server. Having access to the current status of public servers can empower your applications to make decisions and respond to problems automatically. Acknowledging a service is offline can also save endless support emails. In this tutorial, I’ll show you how to keep track of your server status by scanning ports on your server with PHP.
What is server status?
A web application runs on a web server, such as the Apache HTTP server. However, your website often relies on many other “servers” on the same physical server – for example, your email servers, or your database server. Server status checking is commonly found in web hosting control panels, where it is crucial to be aware of the status of services:

Each of these services running on the server is listening on a particular port. We can easily check if the service is online by checking if it is still listening on that particular port. Should it be offline for any reason, we will simply receive no response on that port.
You will be familiar with a simple manual approach for checking the Apache HTTP server – the server by default listens on port 80; if it is offline, a web browser attempting to connect to it will receive no response and will display an error message to the user. You can check your websites are online by attempting to visit them in a web browser. In this tutorial, we will simply automate this process and develop a powerful means for examining server status at a glance.
Service Checking 101
We will be using the PHP function fsockopen() to attempt to open a connection to the port we want to check. If the connection fails, the function will return false. The function also has options to return an error number and an error string if the connection fails. However, a connection does not technically “fail” in a network – or, at least, that is not what we are checking. If the service is offline, the server will simply not respond to the connection and the connection will timeout. We specify how long we want to wait till the connection is considered timed out using a parameter to the function.
Fire up your favourite text editor and copy in the following:
<?php
$connection = @fsockopen("www.google.com", 80);
if ($connection) {
echo "Port 80 on www.google.com is open.";
fclose($connection);
} else {
echo "Port 80 on www.google.com is not open.";
}
In this snippet, we call fsockopen and ask it to open a connection to “www.google.com” on port 80. If the connection is established – fsockopen indicates this by returning a non-false value – we display an appropriate status message, and likewise if the connection is not established. In a variety of situations, the function will output an error message, and so we use the @ symbol before the function name to suppress errors generated.
The function actually returns a handle on a socket connection established, a reference by which you can tell the other socket functions to manipulate this particular connection. In this case, if the connection is established, we need to close the connection, or we could soon overload the server (ours, and theirs!) with an excess of open connections. We achieve this using the fclose function.
Port scanning
As this method is simply checking a particular port on the server, we can easily scan for a number of ports on the server using a simple for loop. This method is known as port scanning. Often a server will be running a range of web-facing services, and server scanning allows server operators to scan for services they may not be aware of. Any web-facing software can bring with it additional security risks, and so port scanning is a popular part of security testing. If we wanted to check all the ports between 1 and 1000 on localhost, we could do this with just a few lines of code:
<?php
for($i=1;$i<=1000;$i++) {
$conn = @fsockopen("localhost", $i);
if ($conn) {
echo "Port $i is open.n";
fclose($conn);
}
}
A simple yet effective implementation.
Our Implementation
To produce something similar to the server status screenshot we saw earlier, we’ll build a simple function to test a given port on the local machine. We’ll then incorporate it into a very basic status interface.
In a production scenario, make sure your testing script is on another server. If your web server goes down, your testing script will as well; if your network is experiencing problems, your testing script will not be able to detect these when scanning the local machine. We’ll use localhost in this example for simplicity’s sake, but seperate hosting for a testing script is crucial in production.
Working with sockets
We can easily give fsockopen a hostname, but we can also give it an IP address. In this case, we probably want to check the local server’s status, but checking service status on a remote server is also an option. We’ll use 127.0.0.1 to check the local server. We also need to make sure we close each connection if we succesfully establish it.
We can build the socket code in a very simple function similar to the port scanning example:
<?php
function check_port($port) {
$conn = @fsockopen("127.0.0.1", $port, $errno, $errstr, 2);
if ($conn) {
fclose($conn);
return true;
}
}
Here we have added a few parameters to the fsockopen function call. The first two, for the error number and string, point to variables that the function can use to store the respective error information. Most important, however, is the ’2′ at the end – this is the timeout for the connection in seconds. If the connection isn’t established in 2 seconds (which should be more than enough for a local connection), the connection attempt is aborted and considered a failure. Keep in mind that, for each service that is offline, the system will wait a further 2 seconds before generating the report. If your page is taking too long to load, the end user may suspect the entire server is offline!
Checking the services
Now, this will do our standard test on whether or not a connection can be established to the local server on the given port. Next, we need a simple system to check for common ports. We can hardcode this section – we’ll always know what we want to check for. Here are some common ports you might want to watch out for:
| 21 | FTP |
| 22 | SSH |
| 25 | SMTP |
| 80 | HTTP |
| 110 | POP3 |
| 143 | IMAP |
| 3306 | MySQL |
This page has a good list of common ports you may find useful.
We can encode these in a simple associative array within a secondary function that generates the status output as another array.
<?php
function server_report() {
$report = array();
$svcs = array('21'=>'FTP',
'22'=>'SSH',
'25'=>'SMTP',
'80'=>'HTTP',
'110'=>'POP3',
'143'=>'IMAP',
'3306'=>'MySQL');
foreach ($svcs as $port=>$service) {
$report[$service] = check_port($port);
}
return $report;
}
$report = server_report();
Using the data
Once this code executes (given the previous check_port function), our $report variable now holds an associative array indexed by the name of the service, with a value of either true or false (well, 0 or 1). We can then very easily display this in a table:
<table>
<tr>
<td>Service</td>
<td>Status</td>
</tr>
<tr>
<td>FTP</td>
<td><?php echo $report['FTP'] ? "Online" : "Offline"; ?></td>
</tr>
<tr>
<td>SSH</td>
<td><?php echo $report['SSH'] ? "Online" : "Offline"; ?></td>
</tr>
...
</table>
And so on. Now that we have a basic system in place, we can easily introduce visual status indicators (e.g. green / red light icons), or do more with the data (e.g. logging).
We’re done!
Here’s the completed code:
<?php
function check_port($port) {
$conn = @fsockopen("127.0.0.1", $port, $errno, $errstr, 0.2);
if ($conn) {
fclose($conn);
return true;
}
}
function server_report() {
$report = array();
$svcs = array('21'=>'FTP',
'22'=>'SSH',
'25'=>'SMTP',
'80'=>'HTTP',
'110'=>'POP3',
'143'=>'IMAP',
'3306'=>'MySQL');
foreach ($svcs as $port=>$service) {
$report[$service] = check_port($port);
}
return $report;
}
$report = server_report();
?>
<table>
<tr>
<td>Service</td>
<td>Status</td>
</tr>
<tr>
<td>FTP</td>
<td><?php echo $report['FTP'] ? "Online" : "Offline"; ?></td>
</tr>
<tr>
<td>SSH</td>
<td><?php echo $report['SSH'] ? "Online" : "Offline"; ?></td>
</tr>
<tr>
<td>SMTP</td>
<td><?php echo $report['SMTP'] ? "Online" : "Offline"; ?></td>
</tr>
<tr>
<td>HTTP</td>
<td><?php echo $report['HTTP'] ? "Online" : "Offline"; ?></td>
</tr>
<tr>
<td>POP3</td>
<td><?php echo $report['POP3'] ? "Online" : "Offline"; ?></td>
</tr>
<tr>
<td>IMAP</td>
<td><?php echo $report['IMAP'] ? "Online" : "Offline"; ?></td>
</tr>
<tr>
<td>MySQL</td>
<td><?php echo $report['MySQL'] ? "Online" : "Offline"; ?></td>
</tr>
</table>
In a production application, you can easily abstract the status checking logic from the report HTML and store service info in a database.
Advanced Status Checking
Now that we’ve built a basic service status checker, we can easily extend it conduct more rigorous testing, and make better use of the data. Here are some possibilities for extending this script:
- Log service data; it can then be graphed or simply archived for auditing
- Report downtime to you, e.g. via email or SMS
- Conduct service-specific testing, e.g. download a HTML page, run a MySQL query, start an FTP session
I mentioned earlier the importance of hosting your testing script away from your actual server; if your project warrants it, storing a testing script on two different servers is great for redundancy, and the two can even work hand in hand to verify if a supposed outage is only region-specific, e.g. a server in the UK might report downtime while a server in the US does not. This can also aid in tracking down the cause of downtime when networks are involved.
Experiment with these techniques, explore additional testing methods and you could be building business-grade status checking systems in no time at all!






One Response to “Port Scanning and Service Status Checking in PHP”
October 10, 2010
Enzo Kunhow to use instead of text online and offline
how about image