diff options
Diffstat (limited to 'modules-available/locations/inc/location.inc.php')
-rw-r--r-- | modules-available/locations/inc/location.inc.php | 141 |
1 files changed, 129 insertions, 12 deletions
diff --git a/modules-available/locations/inc/location.inc.php b/modules-available/locations/inc/location.inc.php index 1a01ff24..4bfe9f7a 100644 --- a/modules-available/locations/inc/location.inc.php +++ b/modules-available/locations/inc/location.inc.php @@ -5,7 +5,17 @@ class Location private static $flatLocationCache = false; private static $assocLocationCache = false; - + private static $treeCache = false; + + private static function getTree() + { + if (self::$treeCache === false) { + self::$treeCache = self::queryLocations(); + self::$treeCache = self::buildTree(self::$treeCache); + } + return self::$treeCache; + } + public static function queryLocations() { $res = Database::simpleQuery("SELECT locationid, parentlocationid, locationname FROM location"); @@ -24,28 +34,31 @@ class Location return false; return self::$assocLocationCache[$locationId]['locationname']; } - + public static function getLocationsAssoc() { if (self::$assocLocationCache === false) { - $rows = self::queryLocations(); - $rows = self::buildTree($rows); + $rows = self::getTree(); self::$assocLocationCache = self::flattenTreeAssoc($rows); } return self::$assocLocationCache; } - - private static function flattenTreeAssoc($tree, $depth = 0) + + private static function flattenTreeAssoc($tree, $parents = array(), $depth = 0) { + if ($depth > 20) { + Util::traceError('Recursive location definition detected at ' . print_r($tree, true)); + } $output = array(); foreach ($tree as $node) { $output[(int)$node['locationid']] = array( 'parentlocationid' => (int)$node['parentlocationid'], + 'parents' => $parents, 'locationname' => $node['locationname'], 'depth' => $depth ); if (!empty($node['children'])) { - $output += self::flattenTreeAssoc($node['children'], $depth + 1); + $output += self::flattenTreeAssoc($node['children'], array_merge($parents, array((int)$node['locationid'])), $depth + 1); } } return $output; @@ -54,8 +67,7 @@ class Location public static function getLocations($default = 0, $excludeId = 0, $addNoParent = false) { if (self::$flatLocationCache === false) { - $rows = self::queryLocations(); - $rows = self::buildTree($rows); + $rows = self::getTree(); $rows = self::flattenTree($rows); self::$flatLocationCache = $rows; } else { @@ -109,6 +121,9 @@ class Location private static function flattenTree($tree, $depth = 0) { + if ($depth > 20) { + Util::traceError('Recursive location definition detected at ' . print_r($tree, true)); + } $output = array(); foreach ($tree as $node) { $output[] = array( @@ -137,7 +152,7 @@ class Location } return $ids; } - + public static function getFromIp($ip) { $locationId = false; @@ -147,11 +162,113 @@ class Location while ($row = $net->fetch(PDO::FETCH_ASSOC)) { $locations = self::getLocationsAssoc(); $id = (int)$row['locationid']; - if (!isset($locations[$id])) continue; - if ($locationId !== false && $locations[$id]['depth'] <= $locations[$locationId]['depth']) continue; + if (!isset($locations[$id])) + continue; + if ($locationId !== false && $locations[$id]['depth'] <= $locations[$locationId]['depth']) + continue; $locationId = $id; } return $locationId; } + /** + * @return array list of subnets as numeric array + */ + public static function getSubnets() + { + $res = Database::simpleQuery("SELECT startaddr, endaddr, locationid FROM subnet"); + $subnets = array(); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + settype($row['locationid'], 'int'); + $subnets[] = $row; + } + return $subnets; + } + + /** + * @return array|bool assoc array mapping from locationid to subnets + */ + public static function getSubnetsByLocation(&$overlapSelf, &$overlapOther) + { + $locs = self::getLocationsAssoc(); + $subnets = self::getSubnets(); + // Find locations having nets overlapping with themselves if array was passed + if ($overlapSelf === true || $overlapOther === true) { + self::findOverlap($locs, $subnets, $overlapSelf, $overlapOther); + } + // Accumulate - copy up subnet definitions + foreach ($locs as &$loc) { + $loc['subnets'] = array(); + } + unset($loc); + foreach ($subnets as $subnet) { + $lid = $subnet['locationid']; + while (isset($locs[$lid])) { + $locs[$lid]['subnets'][] = array( + 'startaddr' => $subnet['startaddr'], + 'endaddr' => $subnet['endaddr'] + ); + $lid = $locs[$lid]['parentlocationid']; + } + } + return $locs; + } + + private static function findOverlap($locs, $subnets, &$overlapSelf, &$overlapOther) + { + if ($overlapSelf) { + $self = array(); + } + if ($overlapOther) { + $other = array(); + } + $cnt = count($subnets); + for ($i = 0; $i < $cnt; ++$i) { + for ($j = $i + 1; $j < $cnt; ++$j) { + if ($overlapSelf && $subnets[$i]['locationid'] === $subnets[$j]['locationid'] + && self::overlap($subnets[$i], $subnets[$j]) + ) { + $self[$subnets[$i]['locationid']] = $subnets[$i]['locationid']; + } + if ($overlapOther && $subnets[$i]['locationid'] !== $subnets[$j]['locationid'] + && self::overlap($subnets[$i], $subnets[$j]) + ) { + $a = min($subnets[$i]['locationid'], $subnets[$j]['locationid']); + $b = max($subnets[$i]['locationid'], $subnets[$j]['locationid']); + $other["$a|$b"] = array('lid1' => $subnets[$i]['locationid'], 'lid2' => $subnets[$j]['locationid']); + } + } + } + if ($overlapSelf) { + $overlapSelf = array(); + foreach ($self as $entry) { + if (!isset($locs[$entry])) + continue; + $overlapSelf[]['locationname'] = $locs[$entry['locationid']]['locationname']; + } + } + if ($overlapOther) { + $overlapOther = array(); + foreach ($other as $entry) { + if (!isset($locs[$entry['lid1']]) || !isset($locs[$entry['lid2']])) + continue; + if (in_array($entry['lid1'], $locs[$entry['lid2']]['parents']) || in_array($entry['lid2'], $locs[$entry['lid1']]['parents'])) + continue; + if (isset($locs[$entry['lid1']])) { + $entry['name1'] = $locs[$entry['lid1']]['locationname']; + } + if (isset($locs[$entry['lid2']])) { + $entry['name2'] = $locs[$entry['lid2']]['locationname']; + } + $overlapOther[] = $entry; + } + } + } + + private static function overlap($net1, $net2) + { + return ($net1['startaddr'] >= $net2['startaddr'] && $net1['startaddr'] <= $net2['endaddr']) + || ($net1['endaddr'] >= $net2['startaddr'] && $net1['endaddr'] <= $net2['endaddr']); + } + } |