This is just a quick tip while I’m moving into our new house (Nykøbing Falster, Denmark). I’ve been writing some security scripts for our router lately to notify me through Pushover when new devices appear on our network and let me block them by Mac with a single click. Don’t worry, we use WPA2-Personal on our WiFi, but we got lots of clients and so do our friends.
As you may have read earlier, have we switched to a 4G LTE connection entirely and run all our internet through this. It works great even through it only delivers 10/0.5 Mbit/sec at the new house, it’s the best we can get, until I’ve mounted a 4G antenna on the roof. I expect it to increase to about 30-50 Mbit/sec down and 10-20 Mbit/sec up when we’ve mounted this as it’s just pure luck (or lack thereof) that our house is right in a blind spot, as you can get full 4G LTE bars 400 meters up the road on a normal cellphone.
I’ve however decided that since I already got the Pi running with cronjobs to monitor our network, I might as well integrate my own Huawei API to get some statistics by the hour about bandwidth usage, ping statistics and internet speeds. Let’s start out by grabbing some ping statistics.
We all know how the linux command ping works. “Ping google.com” is probably the single most written command in internet history, maybe right after “cd” and “ls”. Let’s try it out with some params to automatically stop after a given number of pings. I like to ping 4 times so I have a nice average.
ping -c4 google.com
Which gives us the following output:
PING google.com (184.108.40.206) 56(84) bytes of data.
64 bytes from cache.google.com (220.127.116.11): icmp_req=1 ttl=57 time=177 ms
64 bytes from cache.google.com (18.104.22.168): icmp_req=2 ttl=57 time=305 ms
64 bytes from cache.google.com (22.214.171.124): icmp_req=3 ttl=57 time=133 ms
64 bytes from cache.google.com (126.96.36.199): icmp_req=4 ttl=57 time=82.9 ms
--- google.com ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 82.904/174.914/305.475/82.456 ms
What horrible latency we got while I’m writing this article! Normally it’s around 30-50ms, but when using 4G it’s either all or nothing. Lucky enough it’s mostly “all”, but depending on cell usage and weather conditions, we might get as unlucky as the above.
You can see from the above that we get a nice and clean text output. But how do we actually use this text blob in PHP? I thought somebody had solved this before me, and maybe they have, but I couldn’t find any definitive (and working) answers on either Google or Stackoverflow.
So let’s just use “the magic of TV cooking” and jump to the answer as you are most likely searching for this yourself when reading this blog.
$pingTarget = "google.com";
$pingCount = 4;
//It's very important to escape shell arguments to avoid injection attacks.
$output = shell_exec('ping -c'.escapeshellarg((int)$pingCount).' '.escapeshellarg($pingTarget));
echo "An error occured. Most likely an invalid or unreachable domain.";
//This regex will grab each ping line.
$pingLineRegex = "/([0-9]+) bytes from (.+) \((.+)\): icmp_req=([0-9]+) ttl=([0-9]+) time=([0-9\.]+) ms/";
//This regex grabs the aggregated results at the bottom.
$pingResultRegex = $re = "/--- (.+) ping statistics ---\\n([0-9]+) packets transmitted, ([0-9]+) received, ([0-9\\.]+)% packet loss, time ([0-9]+)ms\\nrtt min\\/avg\\/max\\/mdev = ([0-9\\.]+)\\/([0-9\\.]+)\\/([0-9\\.]+)\\/([0-9\\.]+) ms/";
preg_match_all($pingLineRegex, $output, $pingLineMatches);
$pings = array();
//Array position 0 contains each matched line entirely. We use this to grab the count.
$pingCount = count($pingLineMatches);
$pings = array(
'bytes' => $pingLineMatches[$i],
'host' => $pingLineMatches[$i],
'ip' => $pingLineMatches[$i],
'icmp_req' => $pingLineMatches[$i],
'ttl' => $pingLineMatches[$i],
'time' => $pingLineMatches[$i],
preg_match_all($pingResultRegex, $output, $pingResultMatches);
$pingStatistics = array(
'host' => $pingResultMatches,
'tx' => $pingResultMatches,
'rx' => $pingResultMatches,
'loss' => $pingResultMatches,
'time' => $pingResultMatches,
'min' => $pingResultMatches,
'avg' => $pingResultMatches,
'max' => $pingResultMatches,
'mdev' => $pingResultMatches,
There you go! I thought about making a nice function or class, but this pure code is probably much easier to adopt to your own needs instead of trying to provide a complete solution up front for everybody. The most import thing you are looking for is most likely the two regexes that parse the actual results and how to do error handling.
This script grabs all the data from ping EXCEPT for “Request timed out” lines as I didn’t really care. I’m just going for the $pingStatistics variable!
Thanks for reading and I hope this post helped you out.