Файл: library/XenForo/Model/Ip.php
Строк: 440
<?php
/**
* Model for logging IPs and querying them.
*
* @package XenForo_Ip
*/
class XenForo_Model_Ip extends XenForo_Model
{
/**
* Stores resolved host names from IPs
*
* @var array
*/
protected $_hostCache = array();
/**
* Logs an IP for an action.
*
* @param integer $userId User causing action
* @param string $contentType Type of content (user, post)
* @param integer $contentId ID of content
* @param string $action Action (insert, login)
* @param string|null $ipAddress IP address or null to pull from request
* @param integer|null $date Timestamp to tag IP with
*
* @return integer ID of inserted IP; 0 if no insert
*/
public function logIp($userId, $contentType, $contentId, $action, $ipAddress = null, $date = null)
{
$ipAddress = XenForo_Helper_Ip::getBinaryIp(null, $ipAddress);
if (!$ipAddress)
{
return 0;
}
if ($date === null)
{
$date = XenForo_Application::$time;
}
$this->_getDb()->insert('xf_ip', array(
'user_id' => $userId,
'content_type' => $contentType,
'content_id' => $contentId,
'action' => $action,
'ip' => $ipAddress,
'log_date' => max(0, $date)
));
return $this->_getDb()->lastInsertId();
}
/**
* Static helper to log IPs without creating the model first.
*
* @see XenForo_Model_Ip::logIp()
*/
public static function log($userId, $contentType, $contentId, $action, $ipAddress = null, $date = null)
{
return XenForo_Model::create(__CLASS__)->logIp(
$userId, $contentType, $contentId, $action, $ipAddress, $date
);
}
/**
* Fetches an IP record by its id
*
* @param integer $ipId
*
* @return array
*/
public function getIpById($ipId)
{
$ip = $this->_getDb()->fetchRow('
SELECT * FROM xf_ip
WHERE ip_id = ?
', $ipId);
$ip['ip_address'] = XenForo_Helper_Ip::convertIpBinaryToString($ip['ip']);
return $ip;
}
/**
* Static version of getIpById
*
* @see XenForo_Model_Ip::getIpById()
*/
public static function getById($ipId)
{
return XenForo_Model::create(__CLASS__)->getIpById($ipId);
}
/**
* Returns the first IP logged for the given parameters
*
* @param integer $userId
* @param string $contentType
* @param integer $contentId
*
* @return string IP binary/empty string
*/
public function getIp($userId, $contentType, $contentId)
{
$ip = $this->_getDb()->fetchOne('
SELECT ip
FROM xf_ip
WHERE user_id = ?
AND content_type = ?
AND content_id = ?
', array($userId, $contentType, $contentId));
return ($ip ? XenForo_Helper_Ip::convertIpBinaryToString($ip) : '');
}
/**
* Static helper to get a logged ip wihtout creating the model first
*
* @see XenForo_Model_Ip::getIp()
*/
public static function get($userId, $contentType, $contentId)
{
return XenForo_Model::create(__CLASS__)->getIp(
$userId, $contentType, $contentId
);
}
/**
* Deletes all IPs that belong to the specified content.
*
* @param string $contentType
* @param int|array $contentIds One or more content Ids to delete from
*/
public function deleteByContent($contentType, $contentIds)
{
if (!is_array($contentIds))
{
$contentIds = array($contentIds);
}
if (!$contentIds)
{
return;
}
$db = $this->_getDb();
$db->delete('xf_ip',
'content_type = ' . $db->quote($contentType) . ' AND content_id IN (' . $db->quote($contentIds) . ')'
);
}
protected static $_lookupCache = array();
/**
* Resolves the host name of an IP address
*
* @param string $ip
*
* @return string
*/
protected function _getHost($ip)
{
if (isset(self::$_lookupCache[$ip]))
{
return self::$_lookupCache[$ip];
}
if (strpos($ip, ':') !== false)
{
// we need to uncompress the hex address to split this up
$binary = XenForo_Helper_Ip::convertIpStringToBinary($ip);
if (!$binary)
{
return '';
}
$checkIp = XenForo_Helper_Ip::convertIpBinaryToString($binary, false);
if (!$checkIp)
{
return false;
}
$checkIp = str_replace(':', '', $checkIp);
$parts = str_split($checkIp);
$dnsRecord = implode('.', array_reverse($parts)) . '.ip6.arpa';
}
else
{
$parts = explode('.', $ip);
if (count($parts) != 4)
{
return '';
}
$dnsRecord = implode('.', array_reverse($parts)) . '.in-addr.arpa';
}
$lookup = false;
try
{
if (function_exists('dns_get_record'))
{
$host = dns_get_record($dnsRecord, DNS_PTR);
if (isset($host[0]['target']))
{
$lookup = $host[0]['target'];
}
}
else
{
$lookup = gethostbyaddr($ip);
}
}
catch (Exception $e) {} // bad lookup
if (!$lookup)
{
$lookup = $ip;
}
self::$_lookupCache[$ip] = $lookup;
return $lookup;
}
/**
* Resolves the host name of an IP address
*
* @param string $ip
*
* @return string
*/
public static function getHost($ip)
{
return XenForo_Model::create(__CLASS__)->_getHost($ip);
}
/**
* Gets IP info for a content item and the member who created it
*
* @param array $content
* @param boolean $resolveHosts
*
* @return array (contentIp, contentHost, registrationIp, registrationHost, confirmationIp, confirmationHost)
*/
public function getContentIpInfo(array $content)
{
if ($content['ip_id'])
{
$ip = $this->getIpById($content['ip_id']);
$contentIp = $ip['ip_address'];
$contentHost = $this->_getHost($contentIp);
}
return $this->getRegistrationIps($content['user_id']) + array(
'contentIp' => (empty($contentIp) ? false : $contentIp),
'contentHost' => (empty($contentHost) ? false : $contentHost),
);
}
/**
* Gets IP info for an online user
*
* @param array $onlineUser
*
* @return array (contentIp, contentHost, registrationIp, registrationHost, confirmationIp, confirmationHost)
*/
public function getOnlineUserIp($onlineUser)
{
if ($onlineUser['ip'])
{
$contentIp = XenForo_Helper_Ip::convertIpBinaryToString($onlineUser['ip']);
$contentHost = $this->_getHost($contentIp);
}
return $this->getRegistrationIps($onlineUser['user_id']) + array(
'contentIp' => (empty($contentIp) ? false : $contentIp),
'contentHost' => (empty($contentHost) ? false : $contentHost),
);
}
/**
* Fetches an array containing IP info for the registration and confirmation IPs of the given user
*
* @param integer $userId
*
* @return array (registrationIp, registrationHost, confirmationIp, confirmationHost)
*/
protected function getRegistrationIps($userId)
{
$userIps = $this->getModelFromCache('XenForo_Model_User')->getRegistrationIps($userId);
return array(
'registrationIp' => (empty($userIps['register']) ? false : $userIps['register']),
'registrationHost' => (empty($userIps['register']) ? false : $this->_getHost($userIps['register'])),
'confirmationIp' => (empty($userIps['account-confirmation']) ? false : $userIps['account-confirmation']),
'confirmationHost' => (empty($userIps['account-confirmation']) ? false : $this->_getHost($userIps['account-confirmation'])),
);
}
/**
* Returns an array all IPs used by a user, keyed by the most recent date recorded for that IP
*
* @param integer $userId
*
* @return array [$unixDate => $ip]
*/
public function getIpsByUserId($userId)
{
$ips = $this->_getDb()->fetchPairs('
SELECT MAX(log_date), ip
FROM xf_ip
WHERE user_id = ?
GROUP BY ip
ORDER BY log_date DESC
', $userId);
foreach ($ips AS &$ip)
{
$ip = XenForo_Helper_Ip::convertIpBinaryToString($ip);
}
return $ips;
}
/**
* Searches for records of users using any of the IP addresses logged by the specified user
*
* @param integer ID of the user to check against
* @param integer Number of days to look back in the logs
*
* @return array
*/
public function getSharedIpUsers($userId, $logDays)
{
$db = $this->_getDb();
// written this way due to mysql's ridiculous sub-query performance
$recentIps = $db->fetchCol($db->limit(
'
SELECT DISTINCT ip
FROM xf_ip
WHERE user_id = ?
AND log_date > ?
', 500
), array($userId, XenForo_Application::$time - $logDays * 86400));
if (!$recentIps)
{
return array();
}
$ipLogs = $db->fetchAll($db->limit(
'
SELECT *
FROM xf_ip
WHERE ip IN (' . $db->quote($recentIps) . ')
AND user_id <> ?
AND user_id > 0
AND log_date > ?
ORDER BY log_date DESC
', 1000
), array($userId, XenForo_Application::$time - $logDays * 86400));
$userIpLogs = array();
foreach ($ipLogs AS $ipLog)
{
$ipLog['ip_address'] = XenForo_Helper_Ip::convertIpBinaryToString($ipLog['ip']);
$userIpLogs[$ipLog['user_id']][] = $ipLog;
}
$userRecords = $this->getModelFromCache('XenForo_Model_User')->getUsersByIds(
array_keys($userIpLogs),
array('join' => XenForo_Model_User::FETCH_LAST_ACTIVITY)
);
$visitor = XenForo_Visitor::getInstance();
$users = array();
foreach ($userIpLogs AS $userId => $ipLog)
{
if (!isset($userRecords[$userId]))
{
continue;
}
$users[$userId] = $userRecords[$userId];
$users[$userId]['ipLogs'] = $ipLog;
}
return $users;
}
public function pruneIps($cutOff = null)
{
if ($cutOff === null)
{
if (!XenForo_Application::get('options')->ipLogCleanUp['enabled'])
{
return 0;
}
$cutOff = XenForo_Application::$time - 86400 * XenForo_Application::get('options')->ipLogCleanUp['delay'];
}
$db = $this->_getDb();
return $db->delete('xf_ip', 'log_date < ' . $db->quote($cutOff));
}
}