1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-12 17:54:44 +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(); * $ip = $session->getIP();
* echo $ip; // outputs 111.222.333.444 * 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) * @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. * @return string|int Returns string by default, or integer if $int argument indicates to.
* *
*/ */
public function getIP($int = false, $useClient = false) { public function getIP($int = false, $useClient = false) {
$ip = $this->config->sessionForceIP; $ip = $this->config->sessionForceIP;
$ipv6 = false;
if(!empty($ip)) { if(!empty($ip)) {
// use IP address specified in $config->sessionForceIP and disregard other options // use IP address specified in $config->sessionForceIP and disregard other options
@@ -834,9 +837,9 @@ class Session extends Wire implements \IteratorAggregate {
} else if($useClient) { } else if($useClient) {
if(!empty($_SERVER['HTTP_CLIENT_IP'])) $ip = $_SERVER['HTTP_CLIENT_IP']; 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['HTTP_X_FORWARDED_FOR'])) $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
else if(!empty($_SERVER['REMOTE_ADDR'])) $ip = $_SERVER['REMOTE_ADDR']; else if(!empty($_SERVER['REMOTE_ADDR'])) $ip = $_SERVER['REMOTE_ADDR'];
else $ip = '0.0.0.0'; else $ip = '0.0.0.0';
// It's possible for X_FORWARDED_FOR to have more than one CSV separated IP address, per @tuomassalo // It's possible for X_FORWARDED_FOR to have more than one CSV separated IP address, per @tuomassalo
if(strpos($ip, ',') !== false && $useClient !== 2) { if(strpos($ip, ',') !== false && $useClient !== 2) {
list($ip) = explode(',', $ip); 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, // sanitize: if IP contains something other than digits, periods, commas, spaces,
// then don't use it and instead fallback to the REMOTE_ADDR. // then don't use it and instead fallback to the REMOTE_ADDR.
$test = str_replace(array('.', ',', ' '), '', $ip); $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 { } else {
$ip = $_SERVER['REMOTE_ADDR']; $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) { if($useClient === 2 && strpos($ip, ',') !== false) {
// return multiple IPs // return multiple IPs
$ips = explode(',', $ip); $ips = array();
foreach($ips as $key => $ip) { foreach(explode(',', $ip) as $ip) {
$ip = ip2long(trim($ip)); if($ipv6) {
if(!$int) $ip = long2ip($ip); $ip = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
$ips[$key] = $ip; 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); $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 { } else {
// sanitize by converting to and from integer // sanitize by converting to and from integer
$ip = ip2long(trim($ip)); $ip = ip2long(trim($ip));
@@ -868,7 +903,6 @@ class Session extends Wire implements \IteratorAggregate {
return $ip; return $ip;
} }
/** /**
* Login a user with the given name and password * Login a user with the given name and password
* *

View File

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