Implementing Ping Using ICMP Raw Sockets in PHP
This tutorial explains how to use PHP's raw socket functions to construct and send an ICMP echo request packet, calculate its checksum, receive the reply, and wrap the logic into a reusable ping($host, $retry) function for backend network diagnostics.
To reliably determine whether a remote host is online, the article proposes using ICMP ping instead of checking open ports, which can give false negatives when ports are closed.
An ICMP echo request packet consists of an 8‑bit type, 8‑bit code, 16‑bit checksum, 16‑bit identifier, 16‑bit sequence number, and optional data payload.
First, the packet is built in PHP using raw socket functions:
<code>$package = chr(8).chr(0); // type 8 (echo), code 0
$package .= chr(0).chr(0); // placeholder for checksum
$package .= "R"."C"; // identifier (arbitrary)
$package .= chr(0).chr(1); // sequence number (arbitrary)
for ($i = strlen($package); $i < 64; $i++) {
$package .= chr(0); // pad to 64 bytes
}</code>The checksum is then calculated by treating the packet as an array of 16‑bit words, summing them, folding the overflow, and applying bitwise NOT:
<code>$tmp = unpack("n*", $package);
$sum = array_sum($tmp);
$sum = ($sum >> 16) + ($sum & 0xFFFF);
$sum = $sum + ($sum >> 16);
$sum = ~ $sum;
$checksum = pack("n*", $sum);</code>The computed checksum bytes are inserted back into the packet:
<code>$package[2] = $checksum[0];
$package[3] = $checksum[1]; // fill checksum</code>With the packet ready, a raw socket is created, the packet is sent, and the script waits for a reply using socket_select . Errors such as timeout or socket failures are handled, and the response is parsed to extract length, TTL, sequence number, and round‑trip time:
<code>$socket = socket_create(AF_INET, SOCK_RAW, getprotobyname('icmp'));
$start = microtime();
socket_sendto($socket, $package, strlen($package), 0, $host, 0);
$read = array($socket);
$select = socket_select($read, $write, $except, 5);
// error handling omitted for brevity
socket_recvfrom($socket, $recv, 65535, 0, $host, $port);
$end = microtime();
$recv = unpack("C*", $recv);
$length = count($recv) - 20; // subtract IP header
$ttl = $recv[9];
$seq = $recv[28];
$duration = round(($end - $start) * 1000, 3);
echo "{$length} bytes from {$host}: icmp_seq={$seq} ttl={$ttl} time={$duration}ms\n";
socket_close($socket);</code>Running the script produces output similar to:
<code>64 bytes from 192.168.1.1: icmp_seq=1 ttl=128 time=0.589ms</code>Finally, all the above logic is encapsulated in a reusable function ping($host, $retry = 1) , which can be called from any PHP code to perform a single ICMP ping and return the formatted result.
php中文网 Courses
php中文网's platform for the latest courses and technical articles, helping PHP learners advance quickly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.