PHP: how to check if the client is local?

2019-01-14 23:31发布

问题:

I need to check if a file is opened "locally" (same machine or network). I'm using:

<?php
if ((substr($_SERVER['REMOTE_ADDR'],0,8) == "192.168.") || ($_SERVER['REMOTE_ADDR'] == "127.0.0.1")) {
    // client is local
} else {
    // client is not local
}

But I'm not sure this is the best way.

What is a more foolproof way of doing this?

回答1:

"Foolproof," as always, can be tricky.

If we do restrict ourselves to IPv4, then checking for "127.0.0.1" takes care of the localhost case, but checking against "192.168." is plain wrong - it will only work if the script is being run on a server which happens to be on the 192.168 network, using a 16-bit subnet mask.

Checking $_SERVER['REMOTE_ADDR'] against $_SERVER['SERVER_ADDR'] would be a better bet. This still doesn't take care of the case of a multi-homed host (ie one which has several IP addresses in addition to 127.0.0.1), though.

In order to catch all same-network cases, you'd need to check the combination of SERVER_ADDR and subnet mask against REMOTE_ADDR, but the subnet mask isn't available in $_SERVER.

BUT I found a function which does pretty much what you want here. It's a couple of screens down and it's called clientInSameSubnet. Not my code, but looks right.



回答2:

What Friek said is true, but provided that you know how to get the real client's IP, you can tell if it's a local address using PHP filters:

if ( ! filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) )
{
    // is a local ip address
}


回答3:

In case anyone has trouble finding the above code, suggested by @Uffe, I've included it below:

<?php
/**
* Check if a client IP is in our Server subnet
*
* @param string $client_ip
* @param string $server_ip
* @return boolean
*/
function clientInSameSubnet($client_ip=false,$server_ip=false) {
    if (!$client_ip)
        $client_ip = $_SERVER['REMOTE_ADDR'];
    if (!$server_ip)
        $server_ip = $_SERVER['SERVER_ADDR'];

    // Extract broadcast and netmask from ifconfig
    if (!($p = popen("ifconfig","r"))) return false;
    $out = "";
    while(!feof($p))
        $out .= fread($p,1024);
    fclose($p);

    // This is to avoid wrapping.
    $match  = "/^.*".$server_ip;
    $match .= ".*Bcast:(\d{1,3}\.\d{1,3}i\.\d{1,3}\.\d{1,3}).*";
    $match .= "Mask:(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/im";
    if (!preg_match($match,$out,$regs))
        return false;

    $bcast = ip2long($regs[1]);
    $smask = ip2long($regs[2]);
    $ipadr = ip2long($client_ip);
    $nmask = $bcast & $smask;

    return (($ipadr & $smask) == ($nmask & $smask));
}