代码一:来源于 ThinkPHP 的函数库,我进行了小修改(取X-Forwarded-For中第一个非unknown的有效IP字符串 部分)。通常情况下可用此方法。
/**
* 获取客户端IP
* 修改自 ThinkPHP 函数库
* @staticvar type $ip
* @return string
*/
function get_client_ip()
{
static $ip = NULL;
if ($ip !== NULL)
{
return $ip;
}
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
{
/* 取X-Forwarded-For中第一个非unknown的有效IP字符串 */
$arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach ($arr AS $v)
{
$ip = trim($v);
if ($ip != 'unknown')
{
break;
}
}
}
elseif (isset($_SERVER['HTTP_CLIENT_IP']))
{
$ip = $_SERVER['HTTP_CLIENT_IP'];
}
elseif (isset($_SERVER['REMOTE_ADDR']))
{
$ip = $_SERVER['REMOTE_ADDR'];
}
// IP地址合法验证
$ip = (false !== ip2long($ip)) ? $ip : '0.0.0.0';
return $ip;
}
代码二:来源于 ECShop 的函数库,比方法一多一重判断,当$_SERVER取不到的情况下(不过目前我还不知道什么情况下会取不到。。),使用 getenv() 函数获取。
/**
* 获得用户的真实IP地址
* 来源于 ECShop 函数库
* @return string
*/
function real_ip()
{
static $realip = NULL;
if ($realip !== NULL)
{
return $realip;
}
if (isset($_SERVER))
{
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
{
$arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
/* 取X-Forwarded-For中第一个非unknown的有效IP字符串 */
foreach ($arr AS $ip)
{
$ip = trim($ip);
if ($ip != 'unknown')
{
$realip = $ip;
break;
}
}
}
elseif (isset($_SERVER['HTTP_CLIENT_IP']))
{
$realip = $_SERVER['HTTP_CLIENT_IP'];
}
else
{
if (isset($_SERVER['REMOTE_ADDR']))
{
$realip = $_SERVER['REMOTE_ADDR'];
}
else
{
$realip = '0.0.0.0';
}
}
}
else
{
if (getenv('HTTP_X_FORWARDED_FOR'))
{
$realip = getenv('HTTP_X_FORWARDED_FOR');
}
elseif (getenv('HTTP_CLIENT_IP'))
{
$realip = getenv('HTTP_CLIENT_IP');
}
else
{
$realip = getenv('REMOTE_ADDR');
}
}
preg_match("/[\d\.]{7,15}/", $realip, $onlineip);
$realip = !empty($onlineip[0]) ? $onlineip[0] : '0.0.0.0';
return $realip;
}
好了,现在已经得到客户端 IP 了,我们检查一下是否在允许的 IP 或 IP 段内,通过*通配符进行IP段标识。
/**
* 验证IP是否合法,支持*通配符
* @return boolean
*/
function is_valid_ip()
{
$whitelist = array('192.168.*', '127.0.0.1', '192.168.2.49');//IP白名单列表
$client_ip = '192.168.2.10';//客户端IP
$valid = true; //标识是否合法的ip
//不在白名单中
if (!in_array($client_ip, $whitelist))
{
$valid = false;
foreach ($whitelist as $white)
{
//白名单ip含有*通配符
if (strpos($white, '*') !== false)
{
$valid = true;
$white_arr = explode('.', $white); //白名单ip拆分成数组
$client_ip_arr = explode('.', $client_ip); //要检测的ip拆分成数组
//对应IP段相比较
foreach ($white_arr as $k => $v)
{
if ($v != '*' && $v != $client_ip_arr[$k])
{
$valid = false;
break;
}
}
//经过轮番比较后仍然是true,结束循环白名单
if ($valid == true)
{
break;
}
}
}
}
return $valid;
}