代码一:来源于 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; }