在php中使用gethostbyaddr()函数超时问题

时间:2011-08-07 12:58:54

标签: php

最近我注意到在我的新服务器上gethostbyaddr()函数在我的网站上用来获取referes的主机,它使页面加载速度慢了5倍。

当我删除它时,超时问题就消失了

这个函数和我的新Centos linux服务器配置有什么问题。

还有什么我可以使用而不是这个PHP函数来获取我的引用者的主机名。

7 个答案:

答案 0 :(得分:6)

它可能是DNS解析的暂时缓慢,它可能会在以后清除。除了从PHP进行如下系统调用之外,确实没有gethostbyaddr()的替代方法。 (gethostbyaddr()无论如何基本上都是这样做的)

`nslookup $ip_address`
// Or
`host $ip_address`

您可以使用以下命令测试命令行中的分辨率是否较慢:

# choose an IP address you know the resolution of...
$ host 123.123.123.123

如果这不能快速返回,则可能存在DNS问题。

检查/etc/resolv.conf的内容,如果您有备用DNS服务器,则可以将其指向,请尝试使用该服务器。

答案 1 :(得分:3)

我为gethostbyaddr()写了这个有用的替代品:

//faster alternative to gethostbyaddr()
private function gethost( $ip )
{
    //Make sure the input is not going to do anything unexpected
    //IPs must be in the form x.x.x.x with each x as a number

    if( preg_match( '/^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(?:[.](?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)){3}$/', $ip ) )
    {
        $host = `host -s -W 1 $ip`;
        $host = ( $host ? end( explode( ' ', trim( trim( $host ), '.' ) ) ) : $ip );
        if( in_array( $host, Array( 'reached', 'record', '2(SERVFAIL)', '3(NXDOMAIN)' ) ) )
        {
            return sprintf( '(error fetching domain name for %s)', $ip );
        }
        else
        {
            return $host;
        }
    }
    else
    {
        return '(invalid IP address)';
    }
}

诀窍是使用主机功能,但你必须检查$ ip是否是真正的IP以避免漏洞利用。 我将时间设置为1秒。

它比使用gethostbyaddr快得多,尽管在循环中使用它仍然很慢。

答案 2 :(得分:1)

你有什么样的网络托管服务?共享,VPS或专用。 gethostbyaddr()性能取决于您的Web服务器DNS解析的效果。有些情况可能会降低其性能,但您仍需要至少说出您正在使用的托管类型。

答案 3 :(得分:0)

我认为你应该为gethostbyaddr()结果实现某种类型的缓存系统(好吧,大多数DNS服务器都有内置的缓存系统,但是你可以出于某种原因出现故障)或尝试使用备用DNS服务器(带有使用PHP的套接字进行系统调用或更好。

答案 4 :(得分:0)

不幸的是,某些isp不会为某些IP地址维护反向dns记录,因此dns查找将始终失败。问题是在放弃之前要等多久。

某些托管服务将gethostbyaddr函数超时设置为short,如果查找不成功,则ip地址将替换主机名。这样可以加快速度,防止显示调用此功能的页面出现长时间延迟。

您应该始终仔细检查不显示主机名的日志条目,因为它们经常表明访问者来自具有恶意Internet活动声誉的IP地址。

答案 5 :(得分:0)

从XP升级到7后,它影响了PHP对IPv4与IPv6的处理(例如,127.0.0.1作为:: 1返回)我已经调整了一些代码来暂时解决这个问题。事实证明我在IPv6补丁上使用了gethostbyaddr,因此它正在为PHP停止计时。

之前...

$ip = ip2long6($ip);
$host = gethostbyaddr($ip);

在...

$host = gethostbyaddr($_SERVER['REMOTE_ADDR']);

您可以使用Xdebug和WinCacheGrind(我使用XAMPP进行本地测试)来查找超时的内容,这是一个快速浏览的视频教程......

http://www.warpconduit.net/2012/09/01/quick-tip-profiling-php-applications-with-xdebug-wincachegrind-xampp-for-windows/

希望这可以节省一些人的理智。 : - )

答案 6 :(得分:0)

由于gethostbyaddr()不支持超时且我的托管设置不允许shell命令,我决定使用本地API:

<?php
$ip = isset($_GET['ip']) ? filter_var($_GET['ip'], FILTER_VALIDATE_IP) : false;
if ($ip) {
    echo json_encode(gethostbyaddr($ip));
}
?>

现在我通过file_get_contents()hostAPI.php发送请求,如下所示:

<?php
// prepare host url
function isSecure() {
    return ((isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || $_SERVER['SERVER_PORT'] == 443) ? 's' : '';
}
$protocol_host = 'http' . isSecure() . '://' . filter_input(INPUT_SERVER, 'HTTP_HOST', FILTER_SANITIZE_URL);
// dns request
$context = stream_context_create(array(
    'http' => array(
        'timeout' => 0.4,// 400 ms
    )
));
$ip = long2ip(mt_rand(0, "4294967295"));
// note: the host url needs public access!
$host = json_decode(@file_get_contents($protocol_host . '/hostAPI.php?ip=' . $ip, false, $context), true);
// output
echo 'IP: ' . $ip . "<br>\n";
echo 'HOST: ' . ($host ? $host : 'Timeout!') . "<br>\n";
echo 'Execution Time: ' . round((microtime(true) - $_SERVER["REQUEST_TIME_FLOAT"])  * 1000) . ' ms';
?>

如您所见,我通过stream_context_create()设置了超时时间。

示例输出:

IP: 56.152.200.204
HOST: Timeout!
Execution Time: 801 ms

IP: 81.139.131.130
HOST: host81-139-131-130.range81-139.btcentralplus.com
Execution Time: 52 ms

我不知道为什么,但在我的设置中,0.4超时在&gt;之后启动800毫秒因此我需要将值加倍以获得最终超时。也许其他人可以发表评论。

警告
这会在您的服务器上为主脚本上的每个请求创建一个额外的http请求!