download this file: class.icmp.php view text/plain: class.icmp.php file encoding: UTF-8 [goback]
<?php
##
## this file name is 'class.ping.php'
##
## ping object
##
## [author]
## - http://linuxchannel.net/
##
## [changes]
## - 2014.12.09 : timeout tunning
## - 2008.12.01 : new build
##
## [references]
## - http://kr.php.net/manual/en/function.socket-create.php
## - https://github.com/ErikDubbelboer/php-net-tools/ // good
##
## [usage]
##
## [example]
##
class icmp
{
// timeout in (seconds, microtime)
public function &ping($host, $timeout=array(1,0))
{
static $port = 0;
static $datasize = 58; // default 58 bytes + 8 = 64 bytes
$ident = array(ord('J'), ord('C'));
$seq = array(rand(0, 255), rand(0, 255));
$timeout = array('sec'=>$timeout[0], 'usec'=>$timeout[1]);
## 8 bytes of ICMP header data
$packet = '';
$packet .= chr(8); // type = 8 : request
$packet .= chr(0); // code = 0
$packet .= chr(0); // checksum init
$packet .= chr(0); // checksum init
$packet .= chr($ident[0]); // identifier
$packet .= chr($ident[1]); // identifier
$packet .= chr($seq[0]); // seq
$packet .= chr($seq[1]); // seq
for($i=0; $i<$datasize; $i++) $packet .= chr(0);
$chk = icmp::icmpchecksum($packet);
$packet[2] = $chk[0]; // checksum init
$packet[3] = $chk[1]; // checksum init
if(preg_match('/[a-z]/',$host)) $host = gethostbyname($host); // to ip
if(!$sock = @socket_create(AF_INET, SOCK_RAW, getprotobyname('icmp')))
{
return array(-2, socket_last_error());
}
//@socket_set_option($sock,SOL_SOCKET,SO_REUSEADDR,1);
@socket_set_option($sock,SOL_SOCKET,SO_RCVTIMEO,$timeout); // good idea for blocking mode
@socket_set_option($sock,SOL_SOCKET,SO_SNDTIMEO,$timeout);
//@socket_set_option($sock,SOL_SOCKET,SO_LINGER,array('l_onoff'=>1,'l_linger'=>5));
$time_start = microtime();
@socket_sendto($sock, $packet, strlen($packet), 0, $host, $port);
$time_send = microtime();
$read = array($sock);
$select = @socket_select($read, $write=NULL, $except=NULL, $timeout['sec'], $timeout['usec']);
if($select === NULL)
{
@socket_close($sock);
return array(-1, 'Select Error');
}
else if($select === 0)
{
@socket_close($sock);
return array(-1, 'Timeout');
}
$recv = '';
@socket_recvfrom($sock, $recv, 65535, 0, $host, $port);
$time_stop = microtime();
@socket_close($sock);
$recv = unpack('C*', $recv);
// ICMP proto = 1
if($recv[10] !== 1) return array(-1,'Not ICMP packet');
// ICMP response = 0
if($recv[21] !== 0) return array(-1,'Not ICMP response');
if($ident[0] !== $recv[25] || $ident[1] !== $recv[26]) return array(-1,"Bad identification number, $ident[0]=$recv[25], $ident[1]=$recv[26]");
if($seq[0] !== $recv[27] || $seq[1] !== $recv[28]) return array(-1,"Bad sequence number, $seq[0]=>$recv[27], $seq[1]=>$recv[28]");
$ttt = icmp::getms($time_start, $time_send);
$gtt = icmp::getms($time_send, $time_stop);
$rtt = icmp::getms($time_start, $time_stop);
return array("$rtt $ttt $gtt",'');
}
private function &icmpchecksum($data)
{
$bit = unpack('n*', $data);
$sum = array_sum($bit);
if (strlen($data) % 2)
{
$temp = unpack('C*', $data[strlen($data) - 1]);
$sum += $temp[1];
}
$sum = ($sum >> 16) + ($sum & 0xffff);
$sum += ($sum >> 16);
return pack('n*', ~$sum);
}
public function &getms($_start, $_end)
{
$end = explode(' ', $_end);
$start = explode(' ', $_start);
return sprintf('%.3f',(($end[1]+$end[0])-($start[1]+$start[0])) * 1000);
}
private function error($errstr)
{
return error_log($errstr,0);
}
private function &socket_info($socket)
{
$opt = array
(
'SO_DEBUG'=>SO_DEBUG,
'SO_ACCEPTCONN'=>SO_ACCEPTCONN,
'SO_BROADCAST'=>SO_BROADCAST,
'SO_REUSEADDR'=>SO_REUSEADDR,
'SO_KEEPALIVE'=>SO_KEEPALIVE,
'SO_LINGER'=>SO_LINGER,
'SO_OOBINLINE'=>SO_OOBINLINE,
'SO_SNDBUF'=>SO_SNDBUF,
'SO_RCVBUF'=>SO_RCVBUF,
'SO_ERROR'=>SO_ERROR,
'SO_TYPE'=>SO_TYPE,
'SO_DONTROUTE'=>SO_DONTROUTE,
'SO_RCVLOWAT'=>SO_RCVLOWAT,
'SO_RCVTIMEO'=>SO_RCVTIMEO,
'SO_SNDLOWAT'=>SO_SNDLOWAT,
'SO_SNDTIMEO'=>SO_SNDTIMEO,
);
foreach ($opt as $k=>$value)
{
$r = socket_get_option($socket, SOL_SOCKET, $value);
echo "$k : \n";
print_r($r);
echo "\n";
}
}
} // end of class
?>