1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-11 17:24:46 +02:00

Fix issue processwire/processwire-issues#957 add IPv6 address support for $session->getIP() method

This commit is contained in:
Ryan Cramer
2021-08-12 12:02:07 -04:00
parent 572dc0b7ea
commit 48a37bcc5c
2 changed files with 76 additions and 34 deletions

View File

@@ -807,22 +807,25 @@ class Session extends Wire implements \IteratorAggregate {
}
/**
* Get the IP address of the current user (IPv4)
* Get the IP address of the current user
*
* ~~~~~
* $ip = $session->getIP();
* echo $ip; // outputs 111.222.333.444
* ~~~~~
*
* @param bool $int Return as a long integer for DB storage? (default=false)
* @param bool $int Return as a long integer? (default=false)
* - IPv6 addresses cannot be represented as an integer, so please note that using this int option makes it return a CRC32
* integer when using IPv6 addresses (3.0.184+).
* @param bool|int $useClient Give preference to client headers for IP? HTTP_CLIENT_IP and HTTP_X_FORWARDED_FOR (default=false)
* Specify integer 2 to include potential multiple CSV separated IPs (when provided by client).
* - Specify integer 2 to include potential multiple CSV separated IPs (when provided by client).
* @return string|int Returns string by default, or integer if $int argument indicates to.
*
*/
public function getIP($int = false, $useClient = false) {
$ip = $this->config->sessionForceIP;
$ipv6 = false;
if(!empty($ip)) {
// use IP address specified in $config->sessionForceIP and disregard other options
@@ -834,9 +837,9 @@ class Session extends Wire implements \IteratorAggregate {
} else if($useClient) {
if(!empty($_SERVER['HTTP_CLIENT_IP'])) $ip = $_SERVER['HTTP_CLIENT_IP'];
else if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
else if(!empty($_SERVER['REMOTE_ADDR'])) $ip = $_SERVER['REMOTE_ADDR'];
else $ip = '0.0.0.0';
else if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
else if(!empty($_SERVER['REMOTE_ADDR'])) $ip = $_SERVER['REMOTE_ADDR'];
else $ip = '0.0.0.0';
// It's possible for X_FORWARDED_FOR to have more than one CSV separated IP address, per @tuomassalo
if(strpos($ip, ',') !== false && $useClient !== 2) {
list($ip) = explode(',', $ip);
@@ -844,22 +847,54 @@ class Session extends Wire implements \IteratorAggregate {
// sanitize: if IP contains something other than digits, periods, commas, spaces,
// then don't use it and instead fallback to the REMOTE_ADDR.
$test = str_replace(array('.', ',', ' '), '', $ip);
if(!ctype_digit("$test")) $ip = $_SERVER['REMOTE_ADDR'];
if(!ctype_digit("$test")) {
if(strpos($test, ':') !== false) {
// ipv6 allowed
$test = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
$ip = $test === false ? $_SERVER['REMOTE_ADDR'] : $test;
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
}
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
if(strpos($ip, ':') !== false) {
// attempt to identify an IPv4 version when an integer required for return value
if($int && $ip === '::1') {
$ip = '127.0.0.1';
} else if($int && strpos($ip, '.') && preg_match('!(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})!', $ip, $m)) {
$ip = $m[1]; // i.e. 0:0:0:0:0:ffff:192.1.56.10 => 192.1.56.10
} else {
$ipv6 = true;
}
}
if($useClient === 2 && strpos($ip, ',') !== false) {
// return multiple IPs
$ips = explode(',', $ip);
foreach($ips as $key => $ip) {
$ip = ip2long(trim($ip));
if(!$int) $ip = long2ip($ip);
$ips[$key] = $ip;
$ips = array();
foreach(explode(',', $ip) as $ip) {
if($ipv6) {
$ip = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
if($ip !== false && $int) $ip = crc32($ip);
} else {
$ip = ip2long(trim($ip));
if(!$int) $ip = long2ip($ip);
}
if($ip !== false) $ips[] = $ip;
}
$ip = implode(',', $ips);
} else if($ipv6) {
$ip = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
if($ip === false) {
$ip = $int ? 0 : '0.0.0.0';
} else if($int) {
$ip = crc32($ip);
}
} else {
// sanitize by converting to and from integer
$ip = ip2long(trim($ip));
@@ -868,7 +903,6 @@ class Session extends Wire implements \IteratorAggregate {
return $ip;
}
/**
* Login a user with the given name and password
*

View File

@@ -400,7 +400,9 @@ class FieldtypeComments extends FieldtypeMulti {
*/
public function getDatabaseSchema(Field $field) {
$maxIndexLength = $this->wire('database')->getMaxIndexLength();
$database = $this->wire()->database;
$maxIndexLength = $database->getMaxIndexLength();
$websiteSchema = "varchar($maxIndexLength) NOT NULL default ''";
$parentSchema = "int unsigned NOT NULL default 0";
$flagSchema = "int unsigned NOT NULL default 0";
@@ -411,13 +413,13 @@ class FieldtypeComments extends FieldtypeMulti {
$upvoteSchema = "int unsigned NOT NULL default 0";
$downvoteSchema = "int unsigned NOT NULL default 0";
$starsSchema = "tinyint unsigned default NULL";
$ipSchema = "varchar(45) NOT NULL default ''";
$schemaVersion = (int) $field->get('schemaVersion');
$updateSchema = true;
if(!$schemaVersion) {
// add website field for PW 2.3+
$database = $this->wire('database');
$table = $database->escapeTable($field->getTable());
try {
$database->query("ALTER TABLE `$table` ADD website $websiteSchema");
@@ -429,7 +431,6 @@ class FieldtypeComments extends FieldtypeMulti {
if($schemaVersion < 2) {
// add parent_id and flags columns
$database = $this->wire('database');
$table = $database->escapeTable($field->getTable());
try {
$database->query("ALTER TABLE `$table` ADD parent_id $parentSchema");
@@ -442,7 +443,6 @@ class FieldtypeComments extends FieldtypeMulti {
if($schemaVersion < 3) {
// add code column (admin code)
$database = $this->wire('database');
$table = $database->escapeTable($field->getTable());
try {
$database->query("ALTER TABLE `$table` ADD `code` $codeSchema");
@@ -455,7 +455,6 @@ class FieldtypeComments extends FieldtypeMulti {
if($schemaVersion < 4) {
// add subcode column (subscriber code)
$database = $this->wire('database');
$table = $database->escapeTable($field->getTable());
try {
$database->query("ALTER TABLE `$table` ADD `subcode` $subcodeSchema");
@@ -468,7 +467,6 @@ class FieldtypeComments extends FieldtypeMulti {
if($schemaVersion < 5 && $updateSchema) {
// add upvote/downvote columns
$database = $this->wire('database');
$table = $database->escapeTable($field->getTable());
$parentSchema = parent::getDatabaseSchema($field);
try {
@@ -477,7 +475,7 @@ class FieldtypeComments extends FieldtypeMulti {
`comment_id` int unsigned NOT NULL,
`vote` tinyint NOT NULL,
`created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`ip` VARCHAR(15) NOT NULL default '',
`ip` $ipSchema,
`user_id` int unsigned NOT NULL default 0,
PRIMARY KEY (`comment_id`, `ip`, `vote`),
INDEX `created` (`created`)
@@ -506,7 +504,6 @@ class FieldtypeComments extends FieldtypeMulti {
}
if($schemaVersion < 6 && $updateSchema) {
$database = $this->wire('database');
$table = $database->escapeTable($field->getTable());
try {
$database->query("ALTER TABLE `$table` ADD `stars` $starsSchema");
@@ -521,6 +518,17 @@ class FieldtypeComments extends FieldtypeMulti {
}
}
if($schemaVersion < 7 && $updateSchema) {
$table = $database->escapeTable($field->getTable());
try {
$database->query("ALTER TABLE `$table` MODIFY `ip` $ipSchema");
$database->query("ALTER TABLE `{$table}_votes` MODIFY `ip` $ipSchema");
$schemaVersion = 7;
} catch(\Exception $e) {
$this->error($e->getMessage(), Notice::debug);
}
}
$_schemaVersion = (int) $field->get('schemaVersion');
if($_schemaVersion < $schemaVersion) {
$this->message("Updating schema version of '{$field->name}' from $_schemaVersion to $schemaVersion", Notice::log);
@@ -538,7 +546,7 @@ class FieldtypeComments extends FieldtypeMulti {
$schema['sort'] = "int unsigned NOT NULL";
$schema['created'] = "int unsigned NOT NULL";
$schema['created_users_id'] = "int unsigned NOT NULL";
$schema['ip'] = "varchar(15) NOT NULL default ''";
$schema['ip'] = $ipSchema;
$schema['user_agent'] = "varchar($maxIndexLength) NOT NULL default ''";
$schemaVersion = $field->get('schemaVersion');