在PHP中ping网站并返回结果

28

我想创建一个小的 IF 过程,用于检查 Twitter 是否可用(与现在不同),并返回 true 或 false。

帮忙 :)


2
你能不能改成使用HTTP请求,而不是ping呢? - palindrom
8个回答

50
function urlExists($url=NULL)  
{  
    if($url == NULL) return false;  
    $ch = curl_init($url);  
    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);  

    return $httpcode >= 200 && $httpcode < 300;
}  

这是从这篇文章中获取的,介绍了如何使用curl检查URL是否存在。因为Twitter在维护时应提供大于300的错误消息或404,所以这应该能完美地工作。


如果您需要SSL,请查看此帖子https://dev59.com/Em855IYBdhLWcg3wYjSF - eballo

25

这是其中一个:

http://www.planet-source-code.com/vb/scripts/ShowCode.asp?lngWId=8&txtCodeId=1786

另外一个:

function ping($host, $port, $timeout) { 
  $tB = microtime(true); 
  $fP = fSockOpen($host, $port, $errno, $errstr, $timeout); 
  if (!$fP) { return "down"; } 
  $tA = microtime(true); 
  return round((($tA - $tB) * 1000), 0)." ms"; 
}

//Echoing it will display the ping if the host is up, if not it'll say "down".
echo ping("www.google.com", 80, 10);  

9
返回值不好。为什么不在失败时返回0/false/null,在成功时返回表示毫秒数的整数? - Philippe Gerber
2
@Philippe Gerber - 因为我没有写它,但那些是很好的建议。 - karim79
5
Ping使用ICMP协议,不存在“端口”这样的概念。您可以向0个开放TCP端口的主机发送ping请求。 - deejayy
1
当本地主机没有连接互联网时,fsockopen无法工作。它会显示以下错误: 警告:fsockopen():php_network_getaddresses:getaddrinfo失败:找不到此主机。 - Natasha
@karim79 非常感谢。在紧急情况下,我不得不直接在生产模式中使用它,因为项目需要非常短的时间。我按原样使用了它。救了我的命。 - Shahid Rafiq
我使用了一个假域名,但仍然得到了结果。你知道为什么吗?我指的结果应该返回“ms”对吧? - MaXi32

11
使用shell_exec
<?php
$output = shell_exec('ping -c1 google.com');
echo "<pre>$output</pre>";
?>

4
在Linux系统中,你应该使用ping -c1 host或类似的命令进行ping测试。仅使用ping host命令可能无法返回结果。 - Michas
更好的写法:`if ( 0 != ($_result = \`ping -q -c1 google.com >/dev/null 2>&1 ; echo $?\`) ) { echo '失败。'; }` - lucifurious
出于安全原因,许多生产站点都会禁用PHP的shell_exec函数,尽管它很好用。 - MaXi32

7
另一种选择(如果您需要/想要ping而不是发送HTTP请求)是PHP的Ping类。我为此编写了它,它让您可以使用三种受支持的方法之一来ping服务器(某些服务器/环境仅支持其中一种方法)。
示例用法:
require_once('Ping/Ping.php');
$host = 'www.example.com';
$ping = new Ping($host);
$latency = $ping->ping();
if ($latency) {
  print 'Latency is ' . $latency . ' ms';
}
else {
  print 'Host could not be reached.';
}

6

ping 命令几乎在所有操作系统中都可以使用。因此,您可以进行系统调用并获取结果。


1
另一种解决方案:
使用 get_headers 并比较 HTTP 状态码。
function ping(string $url): bool
{
   $headers = get_headers($url);
   $httpCode = intval(substr($headers[0], 9, 3));

   return $httpCode >= 200 && $httpCode < 300;
}

0

这是我使用的 PHP 代码,通常回复如下:

    已传输2个数据包,收到2个,0% 的丢失,时间1089毫秒

因此我使用了以下代码:

    $ping_how_many = 2;
    $ping_result = shell_exec('ping -c '.$ping_how_many.' bing.com');
    if( !preg_match('/'.$ping_how_many.' received/',$ping_result) ){
       echo 'Ping 结果不佳'. PHP_EOL;
        // 跳转到 next1
    } 

这可能会导致 ping: icmp open socket: Permission denied。为了解决这个问题,SELinux必须处于宽容模式。 - Junior Mayhé
在生产环境中使用 shell_exec 在 PHP 中也不是一个好主意。 - MaXi32

0

使用以下函数,您只需使用socket_create发送纯ICMP数据包。我从用户注释那里得到了以下代码。注意:您必须以root身份运行以下内容。

虽然您无法将其放入标准网页中,但可以将其作为cron作业运行并使用结果填充数据库。

因此,如果您需要监视站点,则最适合使用它。

function twitterIsUp() {
    return ping('twitter.com');
}

function ping ($host, $timeout = 1) {
    /* ICMP ping packet with a pre-calculated checksum */
    $package = "\x08\x00\x7d\x4b\x00\x00\x00\x00PingHost";
    $socket = socket_create(AF_INET, SOCK_RAW, 1);
    socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array('sec' => $timeout, 'usec' => 0));
    socket_connect($socket, $host, null);

    $ts = microtime(true);
    socket_send($socket, $package, strLen($package), 0);
    if (socket_read($socket, 255)) {    
        $result = microtime(true) - $ts;
    } else {
        $result = false;
    }
    socket_close($socket);

    return $result;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接