Вы можете использовать итеративный и рекурсивный подход, передав массив source
для нового label
и массив target
для конечного результата с детьми.
Принимая вышеуказанный требуемый формат, без свойства children
в самом внутреннем объекте, этот подход принимает в качестве цели объект с дочерними элементами. Редукционная часть для генерации новой структуры данных принимает только объекты в качестве возвращаемого значения и создает children
при необходимости.
var data = { entity: { entityLabel: "Virtual Reality", parent: [{ entity: { entityLabel: "Artificial Intelligence", parent: [{ entity: { entityLabel: "Information Technology" } }] } }] } },
result = [];
[data].forEach(function iter(source, target) {
return function ({ entity: { entityLabel, parent } }) {
source = [entityLabel, ...source];
if (parent) return parent.forEach(iter(source, target));
source.reduce((t, label) => {
var temp = (t.children = t.children || []).find(o => o.label === label);
if (!temp) {
t.children.push(temp = { label });
}
return temp;
}, target);
}
}([], { children: result }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
][]Вот более короткий и чистый способ получить IP-адрес:[][
] [function get_ip_address(){
foreach (array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key){
if (array_key_exists($key, $_SERVER) === true){
foreach (explode(',', $_SERVER[$key]) as $ip){
$ip = trim($ip); // just to be safe
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false){
return $ip;
}
}
}
}
}
]
[]Надеюсь, это поможет! [
] []Ваш код, кажется, уже довольно полный, я не вижу в нем никаких возможных ошибок (кроме обычных IP-оговорок), я бы изменил функцию []validate_ip()[
], чтобы полагаться на расширение фильтра, хотя:[
public function validate_ip($ip)
{
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false)
{
return false;
}
self::$ip = sprintf('%u', ip2long($ip)); // you seem to want this
return true;
}
]
[]Также ваш фрагмент []HTTP_X_FORWARDED_FOR[
] можно упростить следующим образом:[
// check for IPs passing through proxies
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
{
// check if multiple ips exist in var
if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',') !== false)
{
$iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach ($iplist as $ip)
{
if ($this->validate_ip($ip))
return $ip;
}
}
else
{
if ($this->validate_ip($_SERVER['HTTP_X_FORWARDED_FOR']))
return $_SERVER['HTTP_X_FORWARDED_FOR'];
}
}
]
[]К этому:[
] [// check for IPs passing through proxies
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
{
$iplist = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach ($iplist as $ip)
{
if ($this->validate_ip($ip))
return $ip;
}
}
]
[]Вы также можете захотеть проверить IPv6-адреса.[
].Я удивлен, что никто не упомянул filter_input, таким образом, вот ответ Alix Axel сжат к короткому:
function get_ip_address(&$keys = ['HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'HTTP_CLIENT_IP', 'REMOTE_ADDR'])
{
return empty($keys) || ($ip = filter_input(INPUT_SERVER, array_pop($keys), FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE))? $ip : get_ip_address($keys);
}
Вы в значительной степени ответили на свой вопрос! :)
function getRealIpAddr() {
if(!empty($_SERVER['HTTP_CLIENT_IP'])) //Check IP address from shared Internet
{
$IPaddress = $_SERVER['HTTP_CLIENT_IP'];
}
elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) //To check IP address is passed from the proxy
{
$IPaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
else
{
$IPaddress = $_SERVER['REMOTE_ADDR'];
}
return $IPaddress;
}
Однако даже в этом случае получение реального IP-адреса пользователя будет ненадежным. Все, что им нужно сделать, это использовать анонимный прокси-сервер (тот, который не учитывает заголовки для http_x_forwarded_for, http_forwarded и т. Д.), И все, что вы получите, это IP-адрес их прокси-сервера.
Затем вы можете увидеть, есть ли список IP-адресов прокси-сервера, которые являются анонимными, но нет никакого способа быть уверенным, что они также на 100% точны, и самое большее, что он сделает, - это сообщить вам, что это прокси-сервер. А если кто-то сообразителен, он может подделать заголовки для пересылки HTTP.
Допустим, мне не нравится местный колледж. Я выясняю, какие IP-адреса они зарегистрировали, и получаю их IP-адреса, запрещенные на вашем сайте, делая плохие вещи, потому что я понимаю, что вы уважаете пересылки HTTP. Список бесконечен.
Тогда есть, как вы догадались, внутренние IP-адреса, такие как сеть колледжа, о которой я упоминал ранее. Многие используют формат 10.xxx. Итак, все, что вы должны знать, это то, что он был перенаправлен для общей сети.
Тогда я не буду вдаваться в подробности, но динамические IP-адреса больше являются способом широкополосной связи. Так. Даже если вы получите IP-адрес пользователя, ожидайте, что он изменится самое позднее через 2–3 месяца.
Мы используем:
/**
* Get the customer's IP address.
*
* @return string
*/
public function getIpAddress() {
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
return $_SERVER['HTTP_CLIENT_IP'];
} else if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
return trim($ips[count($ips) - 1]);
} else {
return $_SERVER['REMOTE_ADDR'];
}
}
Взрыв на HTTP_X_FORWARDED_FOR произошел из-за странных проблем с обнаружением IP-адресов при использовании Squid.
.Самый большой вопрос - для каких целей?
Ваш код почти настолько полон, насколько это возможно - но я вижу, что если вы заметили, что выглядит как добавленный заголовок прокси, вы используете INSTEAD CLIENT_IP, однако, если вы хотите, чтобы эта информация была использована в целях аудита, тогда будьте предупреждены - ее очень легко подделать.
Конечно, вы никогда не должны использовать IP-адреса для любого вида аутентификации - даже эти адреса могут быть подделаны.
Вы можете получить лучшее измерение клиентского ip-адреса, выдавливая флеш или java-апплет, который соединяется с сервером через неhttp-порт (что, таким образом, выявит прозрачные прокси или случаи, когда вставленные прокси-заголовки ложны - но имейте в виду, что, когда клиент может ТОЛЬКО соединиться через web-прокси или исходящий порт заблокирован, соединение с апплета не будет установлено.
C.
/**
* Sanitizes IPv4 address according to Ilia Alshanetsky's book
* "php|architect?s Guide to PHP Security", chapter 2, page 67.
*
* @param string $ip An IPv4 address
*/
public static function sanitizeIpAddress($ip = '')
{
if ($ip == '')
{
$rtnStr = '0.0.0.0';
}
else
{
$rtnStr = long2ip(ip2long($ip));
}
return $rtnStr;
}
//---------------------------------------------------
/**
* Returns the sanitized HTTP_X_FORWARDED_FOR server variable.
*
*/
public static function getXForwardedFor()
{
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
{
$rtnStr = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
elseif (isset($HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR']))
{
$rtnStr = $HTTP_SERVER_VARS['HTTP_X_FORWARDED_FOR'];
}
elseif (getenv('HTTP_X_FORWARDED_FOR'))
{
$rtnStr = getenv('HTTP_X_FORWARDED_FOR');
}
else
{
$rtnStr = '';
}
// Sanitize IPv4 address (Ilia Alshanetsky):
if ($rtnStr != '')
{
$rtnStr = explode(', ', $rtnStr);
$rtnStr = self::sanitizeIpAddress($rtnStr[0]);
}
return $rtnStr;
}
//---------------------------------------------------
/**
* Returns the sanitized REMOTE_ADDR server variable.
*
*/
public static function getRemoteAddr()
{
if (isset($_SERVER['REMOTE_ADDR']))
{
$rtnStr = $_SERVER['REMOTE_ADDR'];
}
elseif (isset($HTTP_SERVER_VARS['REMOTE_ADDR']))
{
$rtnStr = $HTTP_SERVER_VARS['REMOTE_ADDR'];
}
elseif (getenv('REMOTE_ADDR'))
{
$rtnStr = getenv('REMOTE_ADDR');
}
else
{
$rtnStr = '';
}
// Sanitize IPv4 address (Ilia Alshanetsky):
if ($rtnStr != '')
{
$rtnStr = explode(', ', $rtnStr);
$rtnStr = self::sanitizeIpAddress($rtnStr[0]);
}
return $rtnStr;
}
//---------------------------------------------------
/**
* Returns the sanitized remote user and proxy IP addresses.
*
*/
public static function getIpAndProxy()
{
$xForwarded = self::getXForwardedFor();
$remoteAddr = self::getRemoteAddr();
if ($xForwarded != '')
{
$ip = $xForwarded;
$proxy = $remoteAddr;
}
else
{
$ip = $remoteAddr;
$proxy = '';
}
return array($ip, $proxy);
}
Мне интересно, возможно ли вы, возможно, вы должны повторять взорванные в обратном порядке http_x_forwarded_for в обратном порядке, поскольку мой опыт был, что IP-адрес пользователя заканчивается в конце списка, разделенного запятыми, поэтому начиная с начала заголовка, У вас больше шансов получить IP-адрес одного из возвращенных прокси, что может по-прежнему разрешить угон для сеанса, так как многие пользователи могут пройти через этот прокси.