diff --git a/README.md b/README.md
index 2c7001be8..7f8e4348e 100644
--- a/README.md
+++ b/README.md
@@ -124,6 +124,30 @@ Docker
Vichan comes with a Dockerfile and docker-compose configuration, the latter aimed primarily at development and testing.
See the `docker/doc.md` file for more information.
+MaxMind support
+------------
+We use MaxMind to retrieve flags for posts. Previously, the country database was stored in `inc/lib/geoip`, but updating it in that location became unmanageable. Now, a MaxMind account is required to download the country database.
+
+### How to Set It Up
+
+1. Follow these instructions to create a free account for using GeoLite2:
+ [Create an Account on MaxMind](https://support.maxmind.com/hc/en-us/articles/4407099783707-Create-an-Account#h_01G4G4NV169TJWFCJ1KGFAM1CD)
+
+2. Download the database using maxmind website
+
+3. (Optional) Install `geoipupdate` to download the database using CLI:
+ [GeoIP Update Installation Guide](https://github.com/maxmind/geoipupdate)
+
+ 1. Edit the `/etc/GeoIP.conf` file to add your API key.
+ 2. Run `geoipupdate`
+
+5. Update path in `$config['maxmind']['db_path']`
+
+6. (Optional) Set up a cron job to automatically update the database:
+ ```
+ 0 0 * * 2,5 geoipupdate
+ ```
+
vichan API
----------
vichan provides by default a 4chan-compatible JSON API. For documentation on this, see:
diff --git a/composer.json b/composer.json
index 4d020047d..4661b165e 100644
--- a/composer.json
+++ b/composer.json
@@ -17,9 +17,9 @@
"lifo/ip": "^1.0",
"gettext/gettext": "^5.5",
"mrclay/minify": "^2.1.6",
- "geoip/geoip": "^1.17",
"dapphp/securimage": "^4.0",
- "erusev/parsedown": "^1.7.4"
+ "erusev/parsedown": "^1.7.4",
+ "geoip2/geoip2": "^2.13"
},
"autoload": {
"classmap": ["inc/"],
@@ -39,6 +39,7 @@
"inc/functions/net.php",
"inc/functions/num.php",
"inc/functions/theme.php",
+ "inc/functions/ip.php",
"inc/context.php"
]
},
diff --git a/composer.lock b/composer.lock
index 742c3cfce..77f01bbcf 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +4,84 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "72e79f203581eea6e6b0455147b25878",
+ "content-hash": "5fc42e63c61b5d69693a300f026d7d58",
"packages": [
+ {
+ "name": "composer/ca-bundle",
+ "version": "1.5.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/ca-bundle.git",
+ "reference": "3b1fc3f0be055baa7c6258b1467849c3e8204eb2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/ca-bundle/zipball/3b1fc3f0be055baa7c6258b1467849c3e8204eb2",
+ "reference": "3b1fc3f0be055baa7c6258b1467849c3e8204eb2",
+ "shasum": ""
+ },
+ "require": {
+ "ext-openssl": "*",
+ "ext-pcre": "*",
+ "php": "^7.2 || ^8.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.10",
+ "phpunit/phpunit": "^8 || ^9",
+ "psr/log": "^1.0 || ^2.0 || ^3.0",
+ "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\CaBundle\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.",
+ "keywords": [
+ "cabundle",
+ "cacert",
+ "certificate",
+ "ssl",
+ "tls"
+ ],
+ "support": {
+ "irc": "irc://irc.freenode.org/composer",
+ "issues": "https://github.com/composer/ca-bundle/issues",
+ "source": "https://github.com/composer/ca-bundle/tree/1.5.3"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-11-04T10:15:26+00:00"
+ },
{
"name": "dapphp/securimage",
"version": "4.0.2",
@@ -64,58 +140,112 @@
"time": "2020-05-30T10:05:48+00:00"
},
{
- "name": "geoip/geoip",
- "version": "v1.17",
+ "name": "erusev/parsedown",
+ "version": "1.7.4",
"source": {
"type": "git",
- "url": "https://github.com/maxmind/geoip-api-php.git",
- "reference": "2053a85c2ed3e7adcbaf0117e26832f57366e370"
+ "url": "https://github.com/erusev/parsedown.git",
+ "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/maxmind/geoip-api-php/zipball/2053a85c2ed3e7adcbaf0117e26832f57366e370",
- "reference": "2053a85c2ed3e7adcbaf0117e26832f57366e370",
+ "url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3",
+ "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3",
"shasum": ""
},
- "conflict": {
- "ext-geoip": "*"
+ "require": {
+ "ext-mbstring": "*",
+ "php": ">=5.3.0"
},
"require-dev": {
- "phpunit/phpunit": "3.7.*",
- "satooshi/php-coveralls": "1.0.*"
+ "phpunit/phpunit": "^4.8.35"
},
"type": "library",
"autoload": {
- "files": [
- "src/geoip.inc",
- "src/geoipcity.inc",
- "src/timezone.php"
- ]
+ "psr-0": {
+ "Parsedown": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Emanuil Rusev",
+ "email": "hello@erusev.com",
+ "homepage": "http://erusev.com"
+ }
+ ],
+ "description": "Parser for Markdown.",
+ "homepage": "http://parsedown.org",
+ "keywords": [
+ "markdown",
+ "parser"
+ ],
+ "support": {
+ "issues": "https://github.com/erusev/parsedown/issues",
+ "source": "https://github.com/erusev/parsedown/tree/1.7.x"
+ },
+ "time": "2019-12-30T22:54:17+00:00"
+ },
+ {
+ "name": "geoip2/geoip2",
+ "version": "v2.13.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/maxmind/GeoIP2-php.git",
+ "reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/maxmind/GeoIP2-php/zipball/6a41d8fbd6b90052bc34dff3b4252d0f88067b23",
+ "reference": "6a41d8fbd6b90052bc34dff3b4252d0f88067b23",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "maxmind-db/reader": "~1.8",
+ "maxmind/web-service-common": "~0.8",
+ "php": ">=7.2"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "3.*",
+ "phpstan/phpstan": "*",
+ "phpunit/phpunit": "^8.0 || ^9.0",
+ "squizlabs/php_codesniffer": "3.*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "GeoIp2\\": "src"
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
- "LGPL 2.1+"
+ "Apache-2.0"
],
"authors": [
{
- "name": "MaxMind, Inc.",
- "email": "support@maxmind.com",
- "homepage": "http://www.maxmind.com/"
+ "name": "Gregory J. Oschwald",
+ "email": "goschwald@maxmind.com",
+ "homepage": "https://www.maxmind.com/"
}
],
- "description": "MaxMind GeoIP PHP API",
- "homepage": "http://dev.maxmind.com/geoip/legacy/downloadable",
+ "description": "MaxMind GeoIP2 PHP API",
+ "homepage": "https://github.com/maxmind/GeoIP2-php",
"keywords": [
+ "IP",
"geoip",
+ "geoip2",
"geolocation",
"maxmind"
],
"support": {
- "issues": "https://github.com/maxmind/geoip-api-php/issues",
- "source": "https://github.com/maxmind/geoip-api-php/tree/master"
+ "issues": "https://github.com/maxmind/GeoIP2-php/issues",
+ "source": "https://github.com/maxmind/GeoIP2-php/tree/v2.13.0"
},
- "abandoned": "geoip2/geoip2",
- "time": "2016-05-16T19:06:50+00:00"
+ "time": "2022-08-05T20:32:58+00:00"
},
{
"name": "gettext/gettext",
@@ -312,6 +442,122 @@
},
"time": "2022-07-12T15:45:54+00:00"
},
+ {
+ "name": "maxmind-db/reader",
+ "version": "v1.11.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/maxmind/MaxMind-DB-Reader-php.git",
+ "reference": "1e66f73ffcf25e17c7a910a1317e9720a95497c7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/maxmind/MaxMind-DB-Reader-php/zipball/1e66f73ffcf25e17c7a910a1317e9720a95497c7",
+ "reference": "1e66f73ffcf25e17c7a910a1317e9720a95497c7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "conflict": {
+ "ext-maxminddb": "<1.11.1,>=2.0.0"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "3.*",
+ "php-coveralls/php-coveralls": "^2.1",
+ "phpstan/phpstan": "*",
+ "phpunit/phpcov": ">=6.0.0",
+ "phpunit/phpunit": ">=8.0.0,<10.0.0",
+ "squizlabs/php_codesniffer": "3.*"
+ },
+ "suggest": {
+ "ext-bcmath": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder",
+ "ext-gmp": "bcmath or gmp is required for decoding larger integers with the pure PHP decoder",
+ "ext-maxminddb": "A C-based database decoder that provides significantly faster lookups"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "MaxMind\\Db\\": "src/MaxMind/Db"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Gregory J. Oschwald",
+ "email": "goschwald@maxmind.com",
+ "homepage": "https://www.maxmind.com/"
+ }
+ ],
+ "description": "MaxMind DB Reader API",
+ "homepage": "https://github.com/maxmind/MaxMind-DB-Reader-php",
+ "keywords": [
+ "database",
+ "geoip",
+ "geoip2",
+ "geolocation",
+ "maxmind"
+ ],
+ "support": {
+ "issues": "https://github.com/maxmind/MaxMind-DB-Reader-php/issues",
+ "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.11.1"
+ },
+ "time": "2023-12-02T00:09:23+00:00"
+ },
+ {
+ "name": "maxmind/web-service-common",
+ "version": "v0.9.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/maxmind/web-service-common-php.git",
+ "reference": "4dc5a3e8df38aea4ca3b1096cee3a038094e9b53"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/maxmind/web-service-common-php/zipball/4dc5a3e8df38aea4ca3b1096cee3a038094e9b53",
+ "reference": "4dc5a3e8df38aea4ca3b1096cee3a038094e9b53",
+ "shasum": ""
+ },
+ "require": {
+ "composer/ca-bundle": "^1.0.3",
+ "ext-curl": "*",
+ "ext-json": "*",
+ "php": ">=7.2"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "3.*",
+ "phpstan/phpstan": "*",
+ "phpunit/phpunit": "^8.0 || ^9.0",
+ "squizlabs/php_codesniffer": "3.*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "MaxMind\\Exception\\": "src/Exception",
+ "MaxMind\\WebService\\": "src/WebService"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Gregory Oschwald",
+ "email": "goschwald@maxmind.com"
+ }
+ ],
+ "description": "Internal MaxMind Web Service API",
+ "homepage": "https://github.com/maxmind/web-service-common-php",
+ "support": {
+ "issues": "https://github.com/maxmind/web-service-common-php/issues",
+ "source": "https://github.com/maxmind/web-service-common-php/tree/v0.9.0"
+ },
+ "time": "2022-03-28T17:43:20+00:00"
+ },
{
"name": "mrclay/minify",
"version": "2.3.3",
@@ -748,10 +994,14 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
- "ext-mbstring": ">=5.4",
- "ext-gd": ">=5.4",
- "ext-pdo": ">=5.4"
+ "php": ">=7.4",
+ "ext-mbstring": ">=7.4",
+ "ext-gd": ">=7.4",
+ "ext-pdo": ">=7.4"
},
"platform-dev": [],
+ "platform-overrides": {
+ "php": "7.4"
+ },
"plugin-api-version": "2.3.0"
}
diff --git a/inc/config.php b/inc/config.php
index c111b7623..454cae4f7 100644
--- a/inc/config.php
+++ b/inc/config.php
@@ -699,6 +699,19 @@
// Attach country flags to posts.
$config['country_flags'] = false;
+ // Maxmind configuration for country_flags
+ $config['maxmind'] = [
+ // Path to the MaxMind GeoLite2 City database file used for IP geolocation.
+ 'db_path' => '/usr/share/GeoIP/GeoLite2-City.mmdb',
+ // Array of preferred locales to use when fetching location data.
+ // The first locale in the array will be prioritized.
+ 'locale' => ['en'],
+ // Default country name to use if no geolocation data is found for the IP address.
+ 'country_fallback' => 'Unknown',
+ // Default country code to use if no geolocation data is found.
+ 'code_fallback' => 'xx',
+ ];
+
// Allow the user to decide whether or not he wants to display his country
$config['allow_no_country'] = false;
diff --git a/inc/functions/ip.php b/inc/functions/ip.php
new file mode 100644
index 000000000..0b2f1a5c8
--- /dev/null
+++ b/inc/functions/ip.php
@@ -0,0 +1,28 @@
+city($ip);
+ $countryCode = strtolower($record->country->isoCode);
+ } catch (Exception $e) {
+ return [
+ $config['maxmind']['code_fallback'],
+ $config['maxmind']['country_fallback'],
+ ];
+ }
+
+ $countryName = $record->country->name;
+
+ if (empty($countryName)) {
+ $countryName = $config['maxmind']['country_fallback'];
+ $countryCode = $config['maxmind']['code_fallback'];
+ }
+
+ return [$countryCode, $countryName];
+}
\ No newline at end of file
diff --git a/inc/lib/geoip/GeoIPv6.dat b/inc/lib/geoip/GeoIPv6.dat
deleted file mode 100644
index c2f3f11bf..000000000
Binary files a/inc/lib/geoip/GeoIPv6.dat and /dev/null differ
diff --git a/post.php b/post.php
index 644be70d4..62b929d10 100644
--- a/post.php
+++ b/post.php
@@ -8,7 +8,7 @@
use Vichan\{Context, WebDependencyFactory};
use Vichan\Data\Driver\{LogDriver, HttpDriver};
use Vichan\Service\{RemoteCaptchaQuery, SecureImageCaptchaQuery};
-use Vichan\Functions\Format;
+use Vichan\Functions\{Format, IP};
/**
* Utility functions
@@ -976,25 +976,11 @@ function delete_cyclical_posts(string $boardUri, int $threadId, int $cycleLimit)
if (!$dropped_post)
if (($config['country_flags'] && !$config['allow_no_country']) || ($config['country_flags'] && $config['allow_no_country'] && !isset($_POST['no_country']))) {
- $gi=geoip_open('inc/lib/geoip/GeoIPv6.dat', GEOIP_STANDARD);
- function ipv4to6($ip) {
- if (strpos($ip, ':') !== false) {
- if (strpos($ip, '.') > 0)
- $ip = substr($ip, strrpos($ip, ':')+1);
- else return $ip; //native ipv6
- }
- $iparr = array_pad(explode('.', $ip), 4, 0);
- $part7 = base_convert(($iparr[0] * 256) + $iparr[1], 10, 16);
- $part8 = base_convert(($iparr[2] * 256) + $iparr[3], 10, 16);
- return '::ffff:'.$part7.':'.$part8;
- }
+ list($flagCode, $flagName) = IP\fetch_maxmind($_SERVER['REMOTE_ADDR']);
- if ($country_code = geoip_country_code_by_addr_v6($gi, ipv4to6($_SERVER['REMOTE_ADDR']))) {
- if (!in_array(strtolower($country_code), array('eu', 'ap', 'o1', 'a1', 'a2')))
- $post['body'] .= "\n".strtolower($country_code)."".
- "\n".geoip_country_name_by_addr_v6($gi, ipv4to6($_SERVER['REMOTE_ADDR']))."";
- }
+ $post['body'] .= "\n".strtolower($flagCode)."".
+ "\n".$flagName."";
}
if ($config['user_flag'] && isset($_POST['user_flag']) && !empty($_POST['user_flag'])) {