Important alert: (current site time 11/22/2014 8:41:46 AM EDT)
 

article

PHP Ping

Email
Submitted on: 8/23/2005 7:26:31 AM
By: Philip Birk-Jensen  
Level: Advanced
User Rating: By 5 Users
Compatibility: PHP 4.0
Views: 115715
author picture
 
     Learn how to send a valid ping to another network device (with a correct ICMP checksum).

 
 
Terms of Agreement:   
By using this article, you agree to the following terms...   
  1. You may use this article in your own programs (and may compile it into a program and distribute it in compiled format for languages that allow it) freely and with no charge.
  2. You MAY NOT redistribute this article (for example to a web site) without written permission from the original author. Failure to do so is a violation of copyright laws.   
  3. You may link to this article from another website, but ONLY if it is not wrapped in a frame. 
  4. You will abide by any additional copyright restrictions which the author may have placed in the article or article's description.
				
PHP Ping
Index
1) Introduction
1.1) Echo Message
2) Sockets
2.1) Socket functions
3) The Package
3.1) Calculating the checksum
3.2) Checksum source code
4) Conclusion
4.1) A code example
a. Sources b. Understanding this article
1. Introduction
Notice: I will change between binary, decimal and hexadecimal notations, but if you let your mouse rest above the number, the 2 other notations will apear. Try moving your mouse over this number: 1010 0001

Before you start, let me warn you, that this may seem as some heavy reading, but hang in there :)
Remember you have to enable socket programming, if you're not sure how this is done, referer to the PHP manual, on installing[1] PHP. This article will walk you through creating a valid ping function in PHP. And in this process I will be covering network programming (shortly, you can always read about that somewhere else) and working with bitwise operations[2]. First off we'll be discussing how a valid ping (or Echo message, of the Internet Control Message Protocol).
1.1 Echo Message
To make a valid ping to another network device, it's important you follow the ICMP standard, they can be found in RFC-792[3]. And yes you're absolutly right RFC documents are just as boring as the dictionary, but sometimes they come in handy. I've decided to run through the standard quickly, so we can move on.
It's build up by 6 fields, which looks like the following:
Type
(8 bit)
Code
(8 bit)
Checksum
(16 bit)
Identifier
(16 bit)
Sequence Number
(16 bit)
Data
(... bit)
Yep, it might seem a little confusing I know, but it's not that hard to understand. It's nothing but a single line of bits, starting with type and ending with data, now let me explain them a little deeper:
  • Type: This defines what kind of message we whish to send. What we want to send is an Echo Request, which has the type 1000, there's a long list[4] of different messages, and their purpose.
  • Code: In our case we set the code to 0000, because the echo message dosn't have any other options. You can compare the Type with the function and the Code with the parameters.
  • Checksum: The checksum[5] is calculated when then package is assembled, to start with we set the checksum to 0000 0000. Then later the checksum is calculated by one's Complement. If you're not use to binary operations, this will be hard to explain, and there's no easy reading on the net, try to google it[6].
  • Identifier: In the original ping program, this is the UNIX process ID, but in our ping it can be anything. Normaly I just set it to 0000 0000, but it's all up to you. In some cases it could be smart to make it unique so you can recongnize your ICMP package.
  • Sequence Number: Again just a number, in our case it's 0000 0000 as the Identifier. But a good use for this, is to increment it if you run more than 1 ping at a time.
  • Data: This can be any data. In our case, we use: "Scarface"
So basicly that is the package we wish to make, for our ping to be correct. The hard thing here is the checksum, we will work with this later on in the article.
2. Sockets
Before we start designing our package (well talking about calculating the checksum), lets talk a little about network programming.
Normally when people talk about network programming, they're talking about TCP/IP or UDP/IP protocols. But we are going to use the ICMP protocol. But enough about that, let's start looking at the functions we'll be using.
2.1 Socket functions
Working with sockets are much like working with a file or a database. So if you're used to working with a database (like MySQL, I know that probably a lot of you are), this wont be that new to you. To start with, I'm going to make a table over the socket functions we'll be using and an equel (well almost) function in MySQL and Filesystem functions (mainly consult the filesystem, but I included MySQL because I'm convinced more people are familiar with those functions):
Socket MySQL File Description
socket_create() - - This function creates a socket, that we can use to connect to other network devices.
socket_connect() mysql_connect() fopen() Make a connection to a host. This needs the resource from the socket_create() function.
socket_write() mysql_query() fwrite() Send a string to the other network device, like writing to a fileor using INSERT INTO in an SQL query.
socket_read() mysql_fetch_??() fread() Read a string send by the other network device..
socket_close() mysql_close() fclose() Closes the socket resource created with the socket_create function.

There is a lot of other network functions, that comes in handy when you'r network programming, but we will only be using the ones above. This article isn't as much a socket article, as it's an article about learning the Internet checksum and how to assemble an easy ICMP package. And to be honest, this article is written for people who already knows a little about network programming (but if you don't, hey it dosn't matter just keep reading, you might learn something).
Lets pretend we've made our package already, so all we need to do is make the connection, send the package and wait for it to return (just as easy as it sounds, try saying that out loud a couple times).
Socket programming
<?php
$socket = socket_create(AF_INET, SOCK_RAW, 1);
socket_connect($socket, "www.google.com", null);
// If you're using below PHP 5, see the manual for the microtime_float
// function. Instead of just using the microtime() function.
$startTime = microtime(true);
socket_send($socket, $package, strLen($package), 0);
if (socket_read($socket, 255)) {
echo round(microtime(true) - $startTime, 4);
}
socket_close($socket);
?>
We start by creating a new socket. This socket uses IPv4(AF_INET), and the data is all handled by the user(SOCK_RAW) using the ICMP protocol(the last 1 represents the ICMP protocol).
Next up we choose an addresse to ping, I've selected google because we can be almost sertain that it's online (and if it's not it's easy to check). The microtime() is just to get a response time.
Then we send our package, and wait for it to return, and if it returns we post the response time (in seconds). Last up we close the socket we created.
3. The Package
Now we come to the hard part. This is a bit more difficult (hehe, notice a bit I'm so funny), because it's not only PHP here, you also need to know something about working with binary numbers. Scroll a bit upwards, and take a look at the 2 links [5] & [6], or well click them here. But lets start with the easy part, making the package with the checksum set to 0000 0000:
Package (before checksum calculation)
<?php
$type= "\x08";
$code= "\x00";
$checksum= "\x00\x00";
$identifier = "\x00\x00";
$seqNumber = "\x00\x00";
$data= "Scarface";
$package = $type.$code.$checksum.$identifier.$seqNumber.$data;
?>
Notice that I use "\x08" instead of ord(8), use what you like but using ord(8) can sometimes make it harder to understand the whole working with bitwise operations thing. But lets move on to the big nasty checksum.
3.1 Calculating the checksum
As I mentioned earlier the checksum is 1's Complement of the whole package. This is done with the following steps (I must admit, that I'm not very good at explaining this):
  • 1) If the length of the string is an odd number, add a 0000.
  • 2) We devide the whole string, 2-by-2 (16 bit, or 2 characters).
  • 3) Add them all together so you get just a single sum.
  • 4) If the sum of the string is more than 16bit, then just add the carrys.
  • 5) Now do the complemented (exchange all the 1's with 0's and vice versa, also called NOT).

1) I got a string of 6 bytes (guess what it says):
0111 0000 | 0110 1000 | 0110 1001 | 0110 1100 | 0110 1001 | 0111 0000

2) To make it easier for myself, I start by adding them up 2-by-2:
0111 0000 0110 1000 0110 1001 0110 1100 0110 1001 0111 0000
3) Then we add them together, 1-by-1 so it's easier to understand:
Carrys: 11        11 1     
1st: 0111 0000 0110 1000
2nd: 0110 1001 0110 1100
Result1: 1101 1001 1101 0100

Carrys: 1 111  1 11 111      
Result1: 1101 1001 1101 0100
3rd: 0110 1001 0111 0000
Result2: 1 0100 0011 0100 0100

4) Now we end up with a result that is longer than 16bit, so we will take the all above the 16 bits, and add it to the lower bits:
Carrys: 1 111  1 11 111      
High: 0000 0000 0000 0001
Lower: 0100 0011 0100 0100
Result2: 0100 0011 0100 0101

5) And the last thing to do is to take the complemented:
Result2: 0100 0011 0100 0101
NOT:
Final: 1011 1100 1011 1010


Okay, well now that's over with you're propably a bit frustrated because you didn't get it, but unfortunatly I can't help you that much. Personally it was a long lasting battle, before I finally got how this whole thing works, the only thing I can suggest is that you try to read some articles and notes about Bitwise operations and about the 1's complemented (but start with bitwise operations).
The only difference from my example above, is that I have the example in Binary notation, and not hex which most examples are in. And remember to use that you can get the hex and decimal value when you move your mouse over one of the binary numbers.
3.2 Checksum source code
Now that you've learned how to calculate the 1'st Complemented (or well saved it for later), let's make a function that can calculate this for us. Before I present you with this little wonder of a function, it's a good idea to read up on the following functions (and operators): unpack[7], pack[8] and Bitwise Operators[9]. But enough talk, on with the show:
ICMP Checksum calculator
<?php
function icmpChecksum($data)
{
if (strlen($data)%2)
$data .= "\x00";
 
$bit = unpack('n*', $data);
$sum = array_sum($bit);
 
while ($sum >> 16)
$sum = ($sum >> 16) + ($sum & 0xffff);
 
return pack('n*', ~$sum);
}
?>
Ya I know, again it's not something you just understand as you read it, but you have to look through it a couple of times. But hey I can help you a little, let's walk it through step by step, as when we did it manually:
1) First off we check if the data is of odd length if (strlen($data)%2), and well if it is we add the 0000 value.
2) The unpack() function does all the dirty work here, it splits the string up 2-by-2 (just the way we like it) and throws it into an array.
3) Luckily PHP has the array_sum() function so we don't have to make some ugly loop to sum it all up.
4) Our while loop, will take all the bits above the 16th bit, and add them to the 16 lower bits.
5) And the last thing we do is to perform the not(~) operation. Then the pack() function will swap it all back to a string for us.

Let's do a little testing. Let's try to run our string we calculated manually, and see if the result is the same.
Calculator test
<?php
// oh ya, and if you haven't checked what the string was yet,
// it was "philip" (ya I know, that's me :))
$chk = icmpChecksum("philip");
echo decbin(ord($chk[0])) ." ". decbin(ord($chk[1]));
// I've cheated a little bit, so you can move your mouse over the below output,
// and as always get the hex and dec value and character
?>
Output: 10111100 10111010
Well it seemed to work, so jump on down to the conclusion, where I've thrown a short script together, that pings google.
4. Conclusion
As promissed here's a little example.
4.1 A code example
Ping google
<?php
// Checksum calculation function
function icmpChecksum($data)
{
if (strlen($data)%2)
$data .= "\x00";
 
$bit = unpack('n*', $data);
$sum = array_sum($bit);
 
while ($sum >> 16)
$sum = ($sum >> 16) + ($sum & 0xffff);
 
return pack('n*', ~$sum);
}
// Making the package
$type= "\x08";
$code= "\x00";
$checksum= "\x00\x00";
$identifier = "\x00\x00";
$seqNumber = "\x00\x00";
$data= "Scarface";
$package = $type.$code.$checksum.$identifier.$seqNumber.$data;
$checksum = icmpChecksum($package); // Calculate the checksum
$package = $type.$code.$checksum.$identifier.$seqNumber.$data;
// And off to the sockets
$socket = socket_create(AF_INET, SOCK_RAW, 1);
socket_connect($socket, "www.google.com", null);
// If you're using below PHP 5, see the manual for the microtime_float
// function. Instead of just using the microtime() function.
$startTime = microtime(true);
socket_send($socket, $package, strLen($package), 0);
if (socket_read($socket, 255)) {
echo round(microtime(true) - $startTime, 4) .' seconds';
}
socket_close($socket);
?>
And well this time I can conclude, that it sometimes pays to be patient. It's been a true battle making this article, because I started with nothing but an idea for a ping program in PHP. I learned what I've tried to tell all of your guys here, and I think I ded a fair job(it's always easier to understand things when you knwo the right!). It was mainly the bitwise operations that where the trick for me, and I've tried explaining them the best I could.

a. Sources
[1] http://www.php.net/manual/en/install.php
[2] http://en.wikipedia.org/wiki/Bitwise_operations
[3] http://www.ietf.org/rfc/rfc792.txt
[4] http://www.iana.org/assignments/icmp-parameters
[5] http://www.faqs.org/rfcs/rfc1071.html
[6] http://www.google.com/search?hl=en&q=%22One%27s+Complement%22&btnG=Google+Search
[7] http://www.php.net/manual/en/function.unpack.php
[8] http://www.php.net/manual/en/function.pack.php
[9] http://www.php.net/manual/en/language.operators.bitwise.php

[*] http://ftp.arl.mil/~mike/ping.html :: The Story of the PING Program
b. Understanding this article
Well the only purpose of this section, is to clearify a little something about this article. And it will just be done in no particular order:

- I've colored the codes my self, so if there are some color errors, please just leave some feedback, and I'll fix it. If yuo have any complaints about the colors I've used for the different syntax, then I don't want to hear about it, copy the code into your own favorit PHP editor.
- If you find anything offending, then again don't say a word or I'll get you, and I'll get you good :p
- Well that was about it, understanding this article. Now remember please leave some feadback, nothing says "sweeeeet" like good feedback.
- Philip Birk-Jensen, January 2005 -


Other 2 submission(s) by this author

 


Report Bad Submission
Use this form to tell us if this entry should be deleted (i.e contains no code, is a virus, etc.).
This submission should be removed because:

Your Vote

What do you think of this article (in the Advanced category)?
(The article with your highest vote will win this month's coding contest!)
Excellent  Good  Average  Below Average  Poor (See voting log ...)
 

Other User Comments

8/23/2005 7:29:04 AMPSC Moderators

The author name of the article and your username do not match. Was this sourced elsewhere?

PSC Moderators
(If this comment was disrespectful, please report it.)

 
8/23/2005 7:44:04 AMPhilip Jensen

No this is mine, check my email it should prove it.

Another thing, how come there's // in some of the text: "socket progr // amming, i", when I didn't put it there.
(If this comment was disrespectful, please report it.)

 
8/23/2005 7:49:31 AMPSC Moderators

Wasn't implying anything - just doing my duty. I'm sure you'd rather we were vigilant than let people steal YOUR code and articles! Very nice: it's rare to find such a well-formatted article in our pending submissions list.

PSC Moderators
(If this comment was disrespectful, please report it.)

 
8/25/2005 3:16:27 AMhanya

please send me how to open serial port in php,and how to connect a serial camera into acomputer in php also.
thanks.
(If this comment was disrespectful, please report it.)

 
9/11/2005 12:14:36 AMaLeX^rS

I agree with PSC Moderators, who I don't actually beleive to be a Moderator lol.

Ne way: RAW SOCKETS LOL!!
:)
(If this comment was disrespectful, please report it.)

 
10/6/2005 9:36:21 PMbrokenToy

a really well written article, good simple coding example, excellent research. I'm just gutted that your 5 years younger than me and obviously a much better programmer.
(If this comment was disrespectful, please report it.)

 
4/28/2007 5:50:01 AMthe right one

how about showing us how to ping what we want with this from a text field in a form so any one can use it on a site instead of it having to be set threw the code by the admin of the server each time it useless the way it is !
(If this comment was disrespectful, please report it.)

 
8/14/2007 9:04:39 AMpromd

1st of all: THANK YOU :-) this was what I'm looking for since months!

However, I think there's one little thing missing: what happens if the PC is *not* online?

I added a timeout to the socket:

socket_set_option ( $socket, SOL_SOCKET, SO_RCVTIMEO, array("sec"=>2, "usec"=>0) );
directly before I call socket_connect().

In order to catch the error, you should modify the socket_read()-call to something like...

if (false === (@socket_read($socket, 255))) {
echo "down";
} else {
echo "up";
}

(If this comment was disrespectful, please report it.)

 
2/28/2014 2:02:09 PMfroz

execuse me, how can we know that script will work?cause when i try to look at my eth0 with wireshark, i don't see any icmp protocol has been sent. can you tell me how to see it works?(i am a beginner)
(If this comment was disrespectful, please report it.)

 

Add Your Feedback
Your feedback will be posted below and an email sent to the author. Please remember that the author was kind enough to share this with you, so any criticisms must be stated politely, or they will be deleted. (For feedback not related to this particular article, please click here instead.)
 

To post feedback, first please login.