0

I am using exec("ping " . $server->ip, $output, $result); function and I am trying to ping several ip addresses and it takes too much time to ping them one by one. Is there faster way in pinging them.

    //In my controller
    $servers = Server::orderBy('created_at', 'desc')->paginate(10);

    foreach ($servers as $server)
    {
        exec("ping " . $server->ip, $output, $result);

        if($result != 0)
        {
          $server->status = 0;
        }
        else
        {
          $server->status = 1;
        }

    }
Grant Gubatan
  • 265
  • 5
  • 14
  • Possible duplicate of [How can I ping a server port with PHP?](https://stackoverflow.com/questions/9841635/how-can-i-ping-a-server-port-with-php) – mleko Aug 07 '17 at 08:16

1 Answers1

2

So here are two methods :

  1. using a batch file
  2. using fsockopen() function

1. using a batch file :

why bother using it, because most of the amount of time is spent in creating a shell every time you call the exec function, so the idea is to create a mini program that loops over your IP addresses at the command line, by calling system PHP command only once, so here's what you need to do and the explanation afterwards. -create a batch file batch.bat in your doucment_root directory, past the following commands into it:

set list=172.30.240.56 172.30.240.57 172.30.240.58
(for %%a in (%list%) do ( 
   ping -n 1 %%a 
));

you can fill the list above by your IP addresses separated by white_spaces. The ping -n 1 is to ping only once, since you need speed

Then in your script, it will be as simple as putting:
echo '<pre>';
exec('cmd /c .\batch.bat',$result);
/* $result is an array of lines of the output that you can easily access
look at the result obtained by using print_r($result); below

you can even make the creation of the batch file, automatically in the PHP script, provided that you have the right permission(which you're likely to hae it since you can run exec) by typing:

$servers = Server::orderBy('created_at', 'desc')->paginate(10);
$batch_string=' set list=';
foreach ($servers as $server)
    $batch_string.=$server->ip.' ';
$batch_string.= "\n (for %%a in (%list%) do ( 
    ping -n 1 %%a 
));";
file_put_contents('batch.bat',$batch_string);
echo '<pre>';
exec('cmd /c .\batch.bat',$result);

I've tested this with www.google.com and 172.30.240.56 and I've got the following result : (please notice that for the second IP address the ping fails)

Array
(
    [0] => 
    [1] => C:\Batch_File_path>set list=www.google.com 172.30.240.56
    [2] => 
    [3] => C:\Batch_File_path>(for %a in (www.google.com 172.30.240.56) do (ping -n 1 %a  ) )
    [4] => 
    [5] => C:\Batch_File_path>(ping -n 1 www.google.com  )
    [6] => 
    [7] => Pinging www.google.com [172.217.23.196] with 32 bytes of data:
    [8] => Reply from 172.217.23.196: bytes=32 time=84ms TTL=48
    [9] => 
    [10] => Ping statistics for 172.217.23.196:
    [11] =>     Packets: Sent = 1, Received = 1, Lost = 0 (0% loss),
    [12] => Approximate round trip times in milli-seconds:
    [13] =>     Minimum = 84ms, Maximum = 84ms, Average = 84ms
    [14] => 
    [15] => C:\Batch_File_path>(ping -n 1 172.30.240.56  )
    [16] => 
    [17] => Pinging 172.30.240.56 with 32 bytes of data:
    [18] => Request timed out.
    [19] => 
    [20] => Ping statistics for 172.30.240.56:
    [21] =>     Packets: Sent = 1, Received = 0, Lost = 1 (100% loss),
)

2. using fsockopen command :

use sockets, it's a built in PHP, so it's faster and easier to maintain and detect errors, here is a sample code for pinging an Ip address

$fp = fsockopen("www.google.com", 80, $errno, $errstr, 30);
if (!$fp) {
    echo "$errstr ($errno)<br />\n";
} else {
    $out = "GET / HTTP/1.1\r\n";
    $out .= "Host: www.google.com\r\n";
    $out .= "Connection: Close\r\n\r\n";
    fwrite($fp, $out);
    while (!feof($fp)) {
        echo fgets($fp, 128);
    }
    fclose($fp);
}
user10089632
  • 5,216
  • 1
  • 26
  • 34