<?php
/**
* tcp_ping.class.php
* Connectivity Ping, sending NOOP Command to Common TCP Service.
*
* @package TcpPing
* @author Andronicus Riyono <hide@address.com>
* @copyright Copyright (c) 2005 Andronicus Riyono <hide@address.com>
* @version 1.0.0
* @license LGPL
*/
/**
* TcpPing
* Connectivity Ping, sending NOOP Command to Common TCP Service.
*
* This class can be used to check connectivity with TCP service ping. Sending NOOP Command
* to widely used TCP service (http, telnet, ftp, mail)
*
* @package TcpPing
* @author Andronicus Riyono <hide@address.com>
* @copyright Copyright (c) 2005 Andronicus Riyono <hide@address.com>
* @version 1.0.0
* @access public
* @license LGPL
*/
class TcpPing
{
/**
* Error Message Container
*
* @var string
*/
var $mErrorMessage;
/**
* Ping Response Time in seconds
*
* @var float
*/
var $mTime;
/**
* Ping Start Time in seconds
*
* @var float
*/
var $mStartTime;
/**
* NOOP command to use
*
* @var string
*/
var $mNoopCommand;
/**
* Response received from pinged remote host
*
* @var string
*/
var $mResponse;
/**
* Remote host IP Address
*
* @var float
*/
var $mTargetAddr;
/**
* Remote host name or IP Address
*
* @var float
*/
var $mTargetHost;
/**
* Remote host port to ping
*
* @var float
*/
var $mTargetPort;
/**
* Target TCP Service
*
* @var float
*/
var $mTargetService;
/**
* Connectivity Ping Timeout in seconds
*
* @var integer
*/
var $mTimeout;
/**
* SocketPing::_GetMicroTime()
*
* @return float Current microtime in seconds as float
*/
function _GetMicroTime()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
/**
* SocketPing::TimerStart()
* Starts the timer
*/
function TimerStart()
{
$this->mStartTime = $this->_GetMicroTime();
}
/**
* SocketPing::TimerStop()
* Stop the timer and assign the value to mTime property
*/
function TimerStop()
{
$timer_stop = $this->_GetMicroTime();
$this->mTime = $timer_stop - $this->mStartTime;
}
/**
* TcpPing::GetTargetAddress()
* Get value of mTargetAddr property. mTargetAddr contains target's IP address
*
* @return string target IP address
*/
function GetTargetAddress()
{
return $this->mTargetAddr;
}
/**
* SocketPing::GetTime()
* Get the value of mTime property
*
* mTime property contains the ping execution time (set by
*
* @param integer $roundPrecision
* @return float Ping Response Time
*/
function GetTime($roundPrecision = 3)
{
$time = round($this->mTime * 1000, $roundPrecision);
$retval = $time > 1 ? "{$time}ms" : "<1ms";
return $retval;
}
/**
* TcpPing::GetErrorMessage()
* Get the value of mErrorMessage property
*
* mErrorMessage property contains error message if the ping failed
* [TcpPing::Ping() returns boolean false]
*
* @return string ErrorMessage
*/
function GetErrorMessage()
{
return $this->mErrorMessage;
}
/**
* TcpPing::GetResponse()
* Get the value of mResponse property
*
* mResponse property contains the response from remote host
* [ if there are any response of course ;) ]
*
* @return string Tcp Ping Response
*/
function GetResponse()
{
return $this->mResponse;
}
/**
* TcpPing::_SetNoopCommand()
* Setting NOOP Command to use
* the NOOP Command list should be written as an array
* even when it only contains single NOOP Command.
*
* @access private
*/
function _SetNoopCommand()
{
switch ($this->mTargetPort)
{
case 21:
$this->mNoopCommand = array("", "NOOP\r\n", "QUIT\r\n");
break;
case 25:
$this->mNoopCommand = array("", "EHLO\r\n", "NOOP\r\n", "QUIT\r\n");
break;
case 80:
$this->mNoopCommand = array("HEAD / HTTP/1.0\r\nConnection: Close\r\n\r\n");
break;
case 110:
$this->mNoopCommand = array("", "QUIT\r\n");
break;
default:
$this->mNoopCommand = array("NOOP\r\n\r\n");
} // switch
}
/**
* TcpPing::TcpPing()
* Constructor of TcpPing class
*
* @param string $host target hostname or ip address
* @param string $service tcp service to ping (http, ftp, etc.)
* @param integer $timeout in seconds
* @access public
*/
function TcpPing($host, $service = 'http', $timeout = 30)
{
$this->mTargetHost = trim($host);
$this->mTargetService = trim($service);
$this->mTimeout = ($timeout > 0) ? $timeout : 30;
}
/**
* TcpPing::Ping()
* Do the ping
*
* @return boolean true on successful ping, and false on failed ping.
*/
function Ping()
{
/**
* Disabling script timeout
*/
set_time_limit(0);
/**
* Setting target port
*/
if (!($this->mTargetPort = getservbyname($this->mTargetService, 'tcp')))
{
$this->mErrorMessage = "No port number associated with the specified Internet service '{$this->mTargetService}'.";
return false;
}
/**
* Setting target IP address
*/
if (preg_match('/^(?:[0-9]{1,3}.){3}[0-9]{1,3}$/', $this->mTargetHost))
{
$this->mTargetAddr = $this->mTargetHost;
}
else
{
$this->mTargetAddr = gethostbyname($this->mTargetHost);
/**
* gethostbyname() returns a string containing the unmodified hostname on failure
*/
if ($this->mTargetAddr == $this->mTargetHost)
{
$this->mErrorMessage = "Could not find host {$this->mTargetHost}.";
return false;
}
}
/**
* Setting no op command
*
* @see TcpPing::_SetNoopCommand()
*/
$this->_SetNoopCommand();
/**
* Create a TCP/IP socket.
*/
$socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (false === $socket)
{
$this->mErrorMessage = "Could not open socket, reason: " . socket_strerror(socket_last_error());
return false;
}
/**
* Setting timeout
*/
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => $this->mTimeout, 'usec' => 0));
/**
* Try to connect to the specified TCP Service
*/
$result = @socket_connect($socket, $this->mTargetAddr, $this->mTargetPort);
if (false === $result)
{
$this->mErrorMessage = trim(socket_strerror(socket_last_error()));
return false;
}
/**
* When the script reach this point, it means the connection is already established.
* Preparing $reply to receive any reply from the TCP Service and starting the timer.
*/
$reply = '';
$this->TimerStart();
foreach($this->mNoopCommand as $command)
{
socket_write($socket, $command, strlen($command));
$buffer = @socket_read($socket, 2048);
if (false !== $buffer)
{
$reply .= $buffer;
}
else
{
$this->mErrorMessage = trim(socket_strerror(socket_last_error()));
return false;
}
}
/**
* When the script reach this point, it means the TCP Service is responding to the NOOP Command
* Stopping the timer, closing the connection, setting the mResponse property, returning true.
*/
$this->TimerStop();
socket_close($socket);
$this->mResponse = $reply;
return true;
}
}
/**
* TcpPingWrapper
* Ping wrapper for processing multiple ping request
*
* @package TcpPing
* @author Andronicus Riyono
* @copyright Copyright (c) 2004 Andronicus Riyono <hide@address.com>
* @version 1.0.0
* @access public
*/
class TcpPingWrapper
{
var $mInfo;
var $mInput;
var $mOutput;
var $mDebug;
/**
* TcpPingWrapper::TcpPingWrapper()
* Constructor of TcpPingWrapper clas
*
* @access public
*/
function TcpPingWrapper()
{
$this->mDebug = false;
$this->mOutput = array();
}
/**
* TcpPingWrapper::ReadInputFile()
* Reads the input from file
*
* @param string $filename path to input file
* @return boolean true when file read succeed, false when failed
*/
function ReadInputFile($filename)
{
if (file_exists($filename))
{
$this->mInput = array();
foreach(file($filename) as $value)
{
$this->mInput[] = rtrim($value);
}
if (false !== $this->mDebug)
{
echo "Success: reading $filename as input.";
}
return true;
}
else
{
if (false !== $this->mDebug)
{
echo "Error: file $filename doesn't exists.";
}
return false;
}
}
/**
* TcpPingWrapper::ReadFormInput()
* Reads the input from form variable
*
* @param string $varname input variable name. Defaults to "hosts" which means $_REQUEST['hosts'] will be used.
* @return boolean true when file read succeed, false when failed
*/
function ReadFormInput($varname = "hosts")
{
$input = $_REQUEST[$varname];
if (is_array($input))
{
foreach($input as $value)
{
$this->mInput[] = rtrim($value);
}
}
else
{
$this->mInput = rtrim($input);
}
}
/**
* TcpPingWrapper::SetInput()
* Set the mInput property
*
* mInput contains target hostname or IP Address.
* mInput may be string or array of string.
*
* @param mixed $input string or array of string. target hostname or IP Address.
*/
function SetInput($input)
{
$this->mInput = $input;
}
/**
* SocketPingWrapper::Ping()
*
* @return boolean true when ping is executed false when ping failed to execute.
*/
function Ping($try = array('http', 'ftp', 'telnet', 'mail'))
{
if (empty($try))
{
$try = array('http', 'ftp', 'telnet', 'mail');
}
else if (!is_array($try))
{
$try = array($try);
}
if (empty($this->mInput))
{
if (false !== $this->mDebug)
{
echo "Error: no ping target specified.";
}
return false;
}
if (!is_array($this->mInput))
{
$this->mInput = array($this->mInput);
}
foreach($this->mInput as $key => $host)
{
$this->mInfo = array();
$up = false;
foreach($try as $service)
{
$tping = new TcpPing($host, $service);
if ($result = $tping->Ping())
{
$up = true;
$this->mInfo[] = "service=$service time=" . $tping->GetTime();
break;
}
else
{
/**
* If current error message is different from the last one, take it.
*/
if (!sizeof($this->mInfo) || $tping->GetErrorMessage() != $this->mInfo[sizeof($this->mInfo)-1])
{
$this->mInfo[] = $tping->GetErrorMessage();
}
}
}
$this->mOutput[] = "$host [" . $tping->GetTargetAddress() . "] is " . ($up ? 'Alive.' : 'Down!!') . ' ' . implode(" ", $this->mInfo);
}
return true;
}
/**
* SocketPingWrapper::GetOutputAsString()
* Ping result(s) as a string
*
* @return string Ping result(s)
* @access public
*/
function GetOutputAsString()
{
return implode("\r\n", $this->mOutput);
}
/**
* SocketPingWrapper::DisplayOutputAsText()
* Display Ping Result(s) as plain text
*
* @access public
*/
function DisplayOutputAsText()
{
echo $this->GetOutputAsString();
}
/**
* SocketPingWrapper::DisplayOutputAsHtml()
* Display Ping Result(s) as html with line breaks (snippet only, no html nor head nor body tags)
*
* @access public
*/
function DisplayOutputAsHtml()
{
echo nl2br(htmlentities($this->GetOutputAsString()));
}
/**
* SocketPingWrapper::DisplayOutputAsHtmlTable()
* Display Ping Result(s) as html with table (snippet only, no html nor head nor body tags)
*
* @access public
*/
function DisplayOutputAsHtmlTable()
{
echo $this->GetOutputAsHtmlTable();
}
/**
* SocketPingWrapper::DisplayOutputAsHtmlFancy()
* Display Ping result(s) as a fancy html table (WARNING: using deprecated style attribute)
*
* @access public
*/
function DisplayOutputAsHtmlFancy($tableSummary = "Ping Result(s)")
{
echo $this->GetOutputAsHtmlFancy();
}
/**
* SocketPingWrapper::GetOutputAsHtmlTable()
* Ping result(s) as a html table (snippet only, no html nor head nor body tags)
*
* @return string Ping result(s) as a html table
* @access public
*/
function GetOutputAsHtmlTable($tableSummary = "Ping Result(s)")
{
$string = $this->GetOutputAsString();
preg_match_all('/^([^\[]*?)\[(.*?)\] is (.*?)(\.|!!)(.*)$/mi', $string, $matches);
$buffer = '<table summary="' . $tableSummary . '">' . "\r\n";
$buffer .= '<tr><th scope="col">Host</th><th scope="col">IP Address</th><th scope="col">Status</th><th scope="col">Additional Info</th></tr>' . "\r\n";
foreach($matches[0] as $key => $value)
{
$buffer .= '<tr><td>' . htmlentities($matches[1][$key]) . '</td><td>' . htmlentities($matches[2][$key]) . '</td><td>' . htmlentities($matches[3][$key]) . '</td><td>' . $matches[5][$key] . '</td></tr>' . "\r\n";
}
$buffer .= '</table>';
return $buffer;
}
/**
* SocketPingWrapper::GetOutputAsHtmlFancy()
* Ping result(s) as a html table (snippet only, no html nor head nor body tags)
*
* @return string Ping result(s) as a fancy html table (WARNING: using deprecated style attribute)
* @access public
*/
function GetOutputAsHtmlFancy($tableSummary = "Ping Result(s)")
{
$string = $this->GetOutputAsString();
preg_match_all('/^([^\[]*?)\[(.*?)\] is (.*?)(\.|!!)(.*)$/mi', $string, $matches);
$buffer = '<table summary="' . $tableSummary . '">' . "\r\n";
$buffer .= '<tr style="background-color:#ddf;"><th scope="col">Host</th><th scope="col">IP Address</th><th scope="col">Status</th><th scope="col">Additional Info</th></tr>' . "\r\n";
foreach($matches[0] as $key => $value)
{
$bg = ($matches[3][$key] == ' Alive') ? '#dfd' : '#fdd';
$buffer .= '<tr style="background-color:' . $bg . ';"><td>' . htmlentities($matches[1][$key]) . '</td><td>' . htmlentities($matches[2][$key]) . '</td><td>' . htmlentities($matches[3][$key]) . '</td><td>' . $matches[5][$key] . '</td></tr>' . "\r\n";
}
$buffer .= '</table>';
return $buffer;
}
/**
* SocketPingWrapper::WriteOutputTextFile()
* Write the ping result(s) to file as a plain text
*
* @param string $filename File to write output to.
*/
function WriteOutputTextFile($filename)
{
$fh = fopen($filename, "w");
fwrite($fh, $this->GetOutputAsString());
fclose($fh);
}
/**
* SocketPingWrapper::WriteOutputHtmlFile()
* Write the ping result(s) to file as a html with line breaks (snippet only, no html nor head nor body tags)
*
* @param string $filename File to write output to.
*/
function WriteOutputHtmlFile($filename)
{
$fh = fopen($filename, "w");
fwrite($fh, nl2br($this->GetOutputAsString()));
fclose($fh);
}
/**
* SocketPingWrapper::WriteOutputHtmlFileFancy()
* Write the ping result(s) to file as a html table (snippet only, no html nor head nor body tags)
*
* @param string $filename File to write output to.
*/
function WriteOutputHtmlFileFancy($filename)
{
$fh = fopen($filename, "w");
fwrite($fh, $this->GetOutputAsHtmlFancy());
fclose($fh);
}
}
?>