有谁知道一种有效而安全的方法来查看这个输入:
$_SERVER['REMOTE_ADDR']
匹配类似于这个不一致过滤器数组的内容(注意200.100.*. .)*可以表示为200.100.*),通配符用*'s:
表示。array(
'192.168.1.*',
'192.168.2.1*',
'10.0.0.*',
'200.100.*.*',
'300.200.*',
)
想法吗?
foreach($instanceSettings['accessControl']['allowedIpV4Addresses'] as $ipV4Address) {
echo 'Now checking against '.$ipV4Address.'.';
// Compare each octet
$ipV4AddressOctets = String::explode('.', $ipV4Address);
$remoteIpV4AddressOctets = String::explode('.', $_SERVER['REMOTE_ADDR']);
$remoteIpV4AddressIsAllowed = true;
for($i = 0; $i < Arr::size($ipV4AddressOctets); $i++) {
echo 'Comparing '.$ipV4AddressOctets[$i].' against '.$remoteIpV4AddressOctets[$i].'.';
if($ipV4AddressOctets[$i] != $remoteIpV4AddressOctets[$i] && $ipV4AddressOctets[$i] != '*') {
echo 'No match.';
$remoteIpV4AddressIsAllowed = false;
break;
}
}
// Get out of the foreach if we've found a match
if($remoteIpV4AddressIsAllowed) {
break;
}
}
我还没有对此进行基准测试,但是我会选择使用网络硬件/软件使用的方法…
将任意*替换为0和255。将ip转换为整数
所以如果255.255.255。*变为255.255.255.0和255.255.255.255然后在这两个ip上执行ip2long函数
则可以将给定的ip转换为长ip。例如:255.255.50.51 into long ip.
比较该ip对应的长ip是否在黑名单中转换后的长ip之间。如果是,则不允许,否则允许。
$ips = array("ip1", "ip2");
foreach($ips as $ip){
$ip1 = str_replace("*", "0", $ip);
$ip2 = str_replace("*", "255", $ip);
$ip1 = ip2long($ip1);
$ip2 = ip2long($ip2);
$givenip = $_GET["ip"];
$givenip = ip2long($givenip);
if($givenip >= $ip1 && $ip <= $givenip){
echo "blacklist ip hit between {$ip1} and {$ip2} on {$ip}";
}
}
去掉星号,只做:
$ips = array('192.168.1.', '10.0.0.');
foreach ($ips as $ip) {
if (strpos($_SERVER['REMOTE_ADDR'], $ip) === 0) {
// match
}
}
这个允许问题中的所有情况加上没有星号的短掩码,如123.123。
/**
* Checks given IP against array of masks like 123.123.123.123, 123.123.*.101, 123.123., 123.123.1*.*
*
* @param $ip
* @param $masks
* @return bool
*/
public static function checkIp($ip, $masks)
{
if (in_array($ip, $masks)) {
return true; // Simple match
} else {
foreach ($masks as $mask) {
if (substr($mask, -1) == '.' AND substr($ip, 0, strlen($mask)) == $mask) {
return true; // Case for 123.123. mask
}
if (strpos($mask, '*') === false) {
continue; // No simple matching and no wildcard in the mask, leaves no chance to match
}
// Breaking into triads
$maskParts = explode('.', $mask);
$ipParts = explode('.', $ip);
foreach ($maskParts as $key => $maskPart) {
if ($maskPart == '*') {
continue; // This triad is matching, continue with next triad
} elseif (strpos($maskPart, '*') !== false) {
// Case like 1*, 1*2, *1
// Let's use regexp for this
$regExp = str_replace('*', ''d{0,3}', $maskPart);
if (preg_match('/^' . $regExp . '$/', $ipParts[$key])) {
continue; // Matching, go to check next triad
} else {
continue 2; // Not matching, Go to check next mask
}
} else {
if ($maskPart != $ipParts[$key]) {
continue 2; // If triad has no wildcard and not matching, check next mask
}
// otherwise just continue
}
}
// We checked all triads and all matched, hence this mask is matching
return true;
}
// We went through all masks and none has matched.
return false;
}
}
为什么不直接使用正则表达式呢?
preg_match("((192''.168''.1)|(10''.0''.0)|(127''.0''.0)''.[012]''d{0,2}|('':'':1))",$_SERVER['REMOTE_ADDR'])
为了好玩,我将对其进行过度设计。嗯,除非你有一个相当长的列表来匹配。
假设您只使用通配符表示"我不关心这个八位字节",那么您可以将数组中的每个条目解析为四个值(每个八位字节一个)。假设使用-1表示通配符,0-255表示完全匹配该值。(如果您需要比O(n)更好的性能,其中n是匹配列表的大小,那么您可以在这里使用更好的数据结构——例如,一个trie。)当然,您只需要做一次,而不是每次请求。
然后可以用同样的方式解析远程地址(除了不使用通配符)。您还可以在这里发现REMOTE_ADDR不是预期的格式。现在检查匹配变得相当简单:
has_match(ip) =
for n in [0 … L.length)
if (-1 == L.n.0 || L.n.0 = ip.0) && (-1 == L.n.1 || L.n.1 == ip.1) && …
return true
return false
(当然这是伪代码)
这个基于preg_match(),您提供了模式和要测试它的主题。
/**
* ip_match("172.30.20.*", "172.30.20.162"); // true
* ip_match("172.30.20", "172.30.20.162"); // true; works if incomplete
* ip_match("172.30.*.12", "172.30.20.12"); // true
* ip_match("172.30.*.12", "172.30.20.11"); // false
* ip_match("172.30.20.*", "172.30.20.*"); // true; wildcards in the subject will match with wildcards in the pattern
* ip_match("172.30.20.12", "172.30.*.*"); // false
*
* @param $pattern The pattern to test against as a string
* @param $subject The input string
*
* @return bool
*
*/
function ip_match($pattern, $subject) {
$pattern = explode(".", trim($pattern, "."));
$pattern = array_pad($pattern, 4, "*");
$subject = explode(".", trim($subject, "."));
$subject = array_pad($subject, 4, "1");
foreach ($pattern as $i => $octet) {
if ($octet != "*" && $subject[$i] != $octet) {
return false;
}
}
return true;
}
<?php
function ipArrCheck($allowedIPArr = [], $IP = '')
{
$IP_ARR = explode('.', $IP);
$resultArr = [];
foreach ($IP_ARR as $IPkey => $IPvalue) {
foreach ($allowedIPArr as $IPArrKey => $IPArrValue) {
$checkIPArr = explode('.', $IPArrValue);
$resultArr[$IPArrKey][$IPkey] = $checkIPArr[$IPkey] == $IP_ARR[$IPkey] || $checkIPArr[$IPkey] == '*';
}
}
foreach ($resultArr as $value) {
if (count(array_unique($value)) == 1 && current($value)) {
return TRUE;
}
}
return FALSE;
}
$MY_IP = '192.168.52.10';
$ALLOWED_IP_ARR = ['127.0.0.1', '192.168.*.*'];
var_dump(ipArrCheck($ALLOWED_IP_ARR, $MY_IP));