Port Scanning and Service Status Checking in PHP
By Akash Mehta2008-06-06
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.
Tutorial Pages:
» Introduction
» Service Checking 101
» Our Implementation
» Advanced Status Checking
