TheFriendlyHacker's avatar

Checking if server (IP) is offline, and some issues I've encountered

I am trying to build a simple Laravel application that will periodically check if a couple of servers are online or offline. I am satisfied with simply pinging the IP address of each server.

I am currently running PHP 7.2 on OS X (using Laravel Valet).

I'm thinking I could use the exec function to ping the IP and then check the output. However, whenever I try to var_dump or dd the output from the exec, I get an empty string.

Below is my code (may or may not be from StackExchange haha):

$ip = "my.server.ip.address";
$ping = exec("ping -c 1 -s 64 -t 64 ".$ip);

dd($ping);

I have also tried this to no avail:

$ip = "my.server.ip.address";
$ping = exec("ping -c 1 -s 64 -t 64 ".$ip, $output);

dd($output);

Any ideas why I might not be getting any output?

0 likes
8 replies
Cronix's avatar

Your code works for me in a basic tinker session

>>> $ping = exec("ping -c 1 -s 64 -t 64 127.0.0.1", $output);

>>> $output
=> [
     "PING 127.0.0.1 (127.0.0.1) 64(92) bytes of data.",
     "72 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.016 ms",
     "",
     "--- 127.0.0.1 ping statistics ---",
     "1 packets transmitted, 1 received, 0% packet loss, time 0ms",
     "rtt min/avg/max/mdev = 0.016/0.016/0.016/0.000 ms",
   ]

Some server firewalls block icmp requests. Are you sure you can actually ping it?

You might have better luck just issuing a GET request to the homepage and checking the response status and time.

TheFriendlyHacker's avatar

@Cronix I can ping them for sure (when I do so from the Terminal on my Mac, I do get a response).

As for your suggestion, that is definitely a possible option. My only concern: I plan on including the ability in my application to add new servers to monitor from the user interface (eg, you'd enter the server's IP and a name for it, and it'll start monitoring it).

Is there a somewhat-easy way to implement something like this going off of your suggestion? Especially since ~75% of the web URL's on my servers would be going through CloudFlare, which will probably return some sort of response even if the original server is down.

Cronix's avatar

Where are you performing this ping from that it doesn't return results? Is there a firewall on that box possibly preventing it from going out onto the internet?

Can you ssh into the server and ping the other server from the cli directly?

TheFriendlyHacker's avatar

I am developing the Laravel app on my Macbook (via Valet), and this is where I am not getting any output from the exec command.

From the same MacBook, I can ping the server from the terminal and get a response ping insert.my.server.ip

Additionally, I have tried pinging it from the command line on another server, and was also able to get a response.

I'm wondering if either a): I'm using the exec command incorrectly (perhaps there's a different way to get output?)

b): There is a permission issue with php on my MacBook. I have chmod'd the entire Laravel app to 777.

Cronix's avatar

If you check my code, it's the same as what you're using except I hardcoded 127.0.0.1 for the test, so your exec() should be fine. I just ran it from a tinker session. Does it work if you ping your localhost?

Snapey's avatar

Especially since ~75% of the web URL's on my servers would be going through CloudFlare, which will probably return some sort of response even if the original server is down.

Well pinging seems odd since all you would be doing is pinging the cloudflare frontend and not the webserver you are trying to test.

Have a look at other comparable services like uptime robot for ideas such as keyword checking.

1 like
TheFriendlyHacker's avatar

Interesting update: I just tested out this PHP script on my Mac locally:

https://github.com/avignat/Check-Server-Status

So I have two servers (let's refer to them as "server1" and "server2"). I have shut down server1, and left server2 online.

Based on that script's source code, it runs fsockopen, using port 80.

When I ping server1's IP address (as in, its actual IP address, not the CloudFlare IP), I get all timeouts (100% packet loss), and I can't SSH into it. But that aforementioned PHP script shows it as online (which is incorrect - that server is definitely offline).

When pinging server2, I get a response, and it also shows as online on that aforementioned PHP script (which is correct).

When I give that PHP script a completely bogus hostname/IP address (for example "asfasfasfsaf.net"), it shows it as offline (which is correct - that host doesn't exist)

Both of my servers are Linux VPS's. I'm wondering if my VPS host could have some sort of configuration on their network that is messing up all of tests I've attempted.

TheFriendlyHacker's avatar
Level 6

I've found an acceptable solution for my needs (StackExchange to the rescue!).

Curl does the trick:

$ch = curl_init($host);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if($httpcode !== 0){
  // Do stuff for the server being online
} else {
  // Do stuff for the server being offline
}

Note: In this case, I'm just checking to see if any HTTP code is returned at all (aka, not 0). Some may prefer to see what specific HTTP code is received (eg, they want to make sure they're getting a 200 or something). In that case, it is quite easy to modify for those needs. For example,

if($httpcode >= 400){
  // Do something for a 400/500 error
} else {
  // Do something for a 200/300 response
}

But in terms of telling whether or not the server is online, this is perfect!

Please or to participate in this conversation.