1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
<?php
/**
* Matomo - free/libre analytics platform
*
* @link https://matomo.org
* @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
namespace Piwik;
use Matomo\Network\IPUtils;
/**
* Contains IP address helper functions (for both IPv4 and IPv6).
*
* As of Piwik 2.9, most methods in this class are deprecated. You are
* encouraged to use classes from the Piwik "Network" component:
*
* @see \Matomo\Network\IP
* @see \Matomo\Network\IPUtils
* @link https://github.com/matomo-org/component-network
*
* As of Piwik 1.3, IP addresses are stored in the DB has VARBINARY(16),
* and passed around in network address format which has the advantage of
* being in big-endian byte order. This allows for binary-safe string
* comparison of addresses (of the same length), even on Intel x86.
*
* As a matter of naming convention, we use `$ip` for the network address format
* and `$ipString` for the presentation format (i.e., human-readable form).
*
* We're not using the network address format (in_addr) for socket functions,
* so we don't have to worry about incompatibility with Windows UNICODE
* and inetPtonW().
*
* @api
*/
class IP
{
/**
* Returns the most accurate IP address available for the current user, in
* IPv4 format. This could be the proxy client's IP address.
*
* @return string IP address in presentation format.
*/
public static function getIpFromHeader()
{
$general = Config::getInstance()->General;
$clientHeaders = @$general['proxy_client_headers'];
if (!is_array($clientHeaders)) {
$clientHeaders = array();
}
$default = '0.0.0.0';
if (isset($_SERVER['REMOTE_ADDR'])) {
$default = $_SERVER['REMOTE_ADDR'];
}
$ipString = self::getNonProxyIpFromHeader($default, $clientHeaders);
return IPUtils::sanitizeIp($ipString);
}
/**
* Returns a non-proxy IP address from header.
*
* @param string $default Default value to return if there no matching proxy header.
* @param array $proxyHeaders List of proxy headers.
* @return string
*/
public static function getNonProxyIpFromHeader($default, $proxyHeaders)
{
$proxyIps = array();
$config = Config::getInstance()->General;
if (isset($config['proxy_ips'])) {
$proxyIps = $config['proxy_ips'];
}
if (!is_array($proxyIps)) {
$proxyIps = array();
}
$shouldReadLastProxyIp = Config::getInstance()->General['proxy_ip_read_last_in_list'] == 1;
if (!$shouldReadLastProxyIp) {
$proxyIps[] = $default;
}
// examine proxy headers
foreach ($proxyHeaders as $proxyHeader) {
if (!empty($_SERVER[$proxyHeader])) {
// this may be buggy if someone has proxy IPs and proxy host headers configured as
// `$_SERVER[$proxyHeader]` could be eg $_SERVER['HTTP_X_FORWARDED_HOST'] and
// include an actual host name, not an IP
if ($shouldReadLastProxyIp) {
$proxyIp = self::getLastIpFromList($_SERVER[$proxyHeader], $proxyIps);
} else {
$proxyIp = self::getFirstIpFromList($_SERVER[$proxyHeader], $proxyIps);
}
if (strlen($proxyIp) && stripos($proxyIp, 'unknown') === false) {
return $proxyIp;
}
}
}
return $default;
}
/**
* Returns the last IP address in a comma separated list, subject to an optional exclusion list.
*
* @param string $csv Comma separated list of elements.
* @param array $excludedIps Optional list of excluded IP addresses (or IP address ranges).
* @return string Last (non-excluded) IP address in the list or an empty string if all given IPs are excluded.
*/
public static function getFirstIpFromList($csv, $excludedIps = null)
{
$p = strrpos($csv, ',');
if ($p !== false) {
$elements = self::getIpsFromList($csv, $excludedIps);
return reset($elements) ?: '';
}
return trim(Common::sanitizeInputValue($csv));
}
public static function getLastIpFromList($csv, $excludedIps = null)
{
$p = strrpos($csv, ',');
if ($p !== false) {
$elements = self::getIpsFromList($csv, $excludedIps);
return end($elements) ?: '';
}
return trim(Common::sanitizeInputValue($csv));
}
private static function getIpsFromList(string $csv, ?array $excludedIps)
{
$result = [];
$elements = explode(',', $csv);
foreach ($elements as $ipString) {
$element = trim(Common::sanitizeInputValue($ipString));
if (empty($element)) {
continue;
}
$ip = \Matomo\Network\IP::fromStringIP(IPUtils::sanitizeIp($element));
if (empty($excludedIps) || (!in_array($element, $excludedIps) && !$ip->isInRanges($excludedIps))) {
$result[] = $element;
}
}
return $result;
}
}
|