Download plugins/GeoIp2/Commands/UpdateRegionCodes.php from Leon4gr45/matomo: direct link, hf CLI and curl.
- Browser
- Download file 8.87 kB
-
https://huggingface.co/spaces/Leon4gr45/matomo/resolve/main/plugins/GeoIp2/Commands/UpdateRegionCodes.php
- Command line
-
hf download hf://spaces/Leon4gr45/matomo/plugins/GeoIp2/Commands/UpdateRegionCodes.php
-
curl -L -o UpdateRegionCodes.php https://huggingface.co/spaces/Leon4gr45/matomo/resolve/main/plugins/GeoIp2/Commands/UpdateRegionCodes.php
8.87 kB
| /** | |
| * 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\Plugins\GeoIp2\Commands; | |
| use Piwik\Development; | |
| use Piwik\Http; | |
| use Piwik\Plugin\ConsoleCommand; | |
| use Piwik\Plugins\GeoIp2\LocationProvider\GeoIp2\Php; | |
| use Piwik\Plugins\UserCountry\LocationProvider; | |
| /** | |
| * This command can be used to update the list of regions and their names that Matomo knows about. | |
| * A list of iso regions is fetched from the iso-codes project. This list will then be used to update the regions array | |
| * located in data/isoRegionNames | |
| * - new regions will be added as current | |
| * - changed names will be updated (adding the previous name as alternate name) | |
| * - removed regions will be kept, but marked as not current | |
| * | |
| * Additionally, this command can be used to add regions that are returned by DB IP GeoIP database | |
| * As the DBIP Lite database only contains region names, but no region codes, we try to map the returned name to a known | |
| * region. As DBIP in some cases returns names, that differ from the official region name, Matomo would be unable to | |
| * store those regions. To provide a better mapping this command allows to provide the --db-ip-csv option. | |
| * This option should provide the path to the DB-IP city lite database in CSV format. In addition, the paid DB-IP city | |
| * (mmdb) database should be configured in Matomo as location provider. | |
| * The command will then iterate through all IP ranges defined in the CSV database and query a look-up using the | |
| * location provider. The returned region iso code and region name is then compared with those included in the regions | |
| * array. Missing regions will be added (as not current), mismatching names will be added as alternate names. | |
| * This will ensure that regions returned by the lite database should be mapped correctly. | |
| * Attention: Using this option will take a couple of hours to process. | |
| */ | |
| class UpdateRegionCodes extends ConsoleCommand | |
| { | |
| public $source = 'https://salsa.debian.org/iso-codes-team/iso-codes/-/raw/main/data/iso_3166-2.json'; | |
| protected function configure() | |
| { | |
| $this->setName('usercountry:update-region-codes'); | |
| $this->setDescription("Updates the ISO region names"); | |
| $this->addOptionalValueOption('db-ip-csv', null, 'Uses the provided DB IP CSV database to iterate over all included IP ranges.'); | |
| } | |
| public function isEnabled() | |
| { | |
| return Development::isEnabled(); | |
| } | |
| protected function doExecute(): int | |
| { | |
| $output = $this->getOutput(); | |
| $input = $this->getInput(); | |
| $regionsFile = __DIR__ . '/../data/isoRegionNames.php'; | |
| $output->setDecorated(true); | |
| $output->writeln('Starting region codes update'); | |
| $output->write('Fetching region codes from ' . $this->source); | |
| try { | |
| $newContent = Http::sendHttpRequest($this->source, 1000); | |
| } catch (\Exception $e) { | |
| $output->writeln(' <fg=red>X (Fetching content failed)</>'); | |
| return self::FAILURE; | |
| } | |
| $regionData = json_decode($newContent, true); | |
| if (empty($regionData)) { | |
| $output->writeln(' <fg=red>X (Content could not be parsed)</>'); | |
| return self::FAILURE; | |
| } | |
| $output->writeln(' <fg=green>β</>'); | |
| $newRegions = []; | |
| foreach ($regionData['3166-2'] as $region) { | |
| list($countryCode, $regionCode) = explode('-', $region['code']); | |
| $newRegions[$countryCode][$regionCode] = [ | |
| 'name' => $region['name'], | |
| 'altNames' => [], | |
| 'current' => true, | |
| ]; | |
| } | |
| ksort($newRegions); | |
| $currentRegions = include $regionsFile; | |
| foreach ($currentRegions as $countryCode => $regions) { | |
| foreach ($regions as $regionCode => $regionData) { | |
| if (isset($newRegions[$countryCode][$regionCode])) { | |
| $newRegions[$countryCode][$regionCode]['altNames'] = $regionData['altNames']; | |
| if ( | |
| $newRegions[$countryCode][$regionCode]['name'] !== $regionData['name'] | |
| && !in_array($regionData['name'], $newRegions[$countryCode][$regionCode]['altNames']) | |
| ) { | |
| $newRegions[$countryCode][$regionCode]['altNames'][] = $regionData['name']; | |
| } | |
| if (($key = array_search($newRegions[$countryCode][$regionCode]['name'], $newRegions[$countryCode][$regionCode]['altNames'])) !== false) { | |
| unset($newRegions[$countryCode][$regionCode]['altNames'][$key]); | |
| $newRegions[$countryCode][$regionCode]['altNames'] = array_values($newRegions[$countryCode][$regionCode]['altNames']); | |
| } | |
| } else { | |
| $newRegions[$countryCode][$regionCode] = $regionData; | |
| $newRegions[$countryCode][$regionCode]['current'] = false; | |
| } | |
| } | |
| } | |
| $dbIpCsvFile = $input->getOption('db-ip-csv'); | |
| if (!empty($dbIpCsvFile)) { | |
| $this->enrichWithDbIpRegions($dbIpCsvFile, $newRegions); | |
| } | |
| if (json_encode($newRegions) === json_encode($currentRegions)) { | |
| $output->writeln(''); | |
| $output->writeln('Everything already up to date <fg=green>β</>'); | |
| return self::SUCCESS; | |
| } | |
| $content = <<<CONTENT | |
| <?php | |
| // The below list contains all ISO region codes and names known to Matomo | |
| // Format: | |
| // <CountryCode> => [ | |
| // <RegionCode> => [ | |
| // 'name' => <CurrentISOName> | |
| // 'altNames' => [ | |
| // // list of previous names or names used by GeoIP providers like db-ip | |
| // ], | |
| // 'current' => <bool> indicating if the iso code is currently used | |
| // ] | |
| // ] | |
| return | |
| CONTENT; | |
| $content .= ' ' . var_export($newRegions, true) . ';' . "\n"; | |
| // strip trailing whitespace so the regenerated file matches the coding style | |
| $content = preg_replace('/[ \t]+$/m', '', $content); | |
| file_put_contents($regionsFile, $content); | |
| $output->writeln('File successfully updated <fg=green>β</>'); | |
| return self::SUCCESS; | |
| } | |
| private function enrichWithDbIpRegions(string $dbIpCsvFile, array &$regions) | |
| { | |
| $output = $this->getOutput(); | |
| $output->writeln('Start looking through GeoIP database for missing region names'); | |
| $php = new Php(); | |
| $supportedInfo = $php->getSupportedLocationInfo(); | |
| if (empty($supportedInfo[LocationProvider::REGION_CODE_KEY])) { | |
| $output->writeln(' <fg=red>X Region codes not supported by currently used GeoIP database. Skipping.</>'); | |
| return; | |
| } | |
| $output->writeln('Iterating through all IPv4 addresses...'); | |
| $this->initProgressBar(8072539); | |
| $handle = fopen($dbIpCsvFile, 'r'); | |
| while (!feof($handle)) { | |
| $csv = str_getcsv(fgets($handle)); | |
| $ip = $csv[0] ?? ''; | |
| $this->advanceProgressBar(); | |
| if (empty($ip)) { | |
| continue; | |
| } | |
| $location = $php->getLocation(['ip' => $ip]); | |
| $countryCode = $location[LocationProvider::COUNTRY_CODE_KEY] ?? null; | |
| $regionCode = $location[LocationProvider::REGION_CODE_KEY] ?? null; | |
| $regionName = $location[LocationProvider::REGION_NAME_KEY] ?? null; | |
| if (empty($countryCode) || empty($regionCode) || empty($regionName)) { | |
| continue; | |
| } | |
| if (!array_key_exists($countryCode, $regions)) { | |
| continue; | |
| } | |
| if (!array_key_exists($regionCode, $regions[$countryCode])) { | |
| $output->writeln(''); | |
| $output->writeln("Adding missing region $regionName ($regionCode) for country $countryCode <fg=green>β</>"); | |
| $regions[$countryCode][$regionCode] = [ | |
| 'name' => $regionName, | |
| 'altNames' => [], | |
| 'current' => false, | |
| ]; | |
| } else { | |
| if ( | |
| $regionName !== $regions[$countryCode][$regionCode]['name'] | |
| && !in_array($regionName, $regions[$countryCode][$regionCode]['altNames']) | |
| ) { | |
| $output->writeln(''); | |
| $output->writeln("Adding alternate region name $regionName to region {$regions[$countryCode][$regionCode]['name']} ($regionCode) for country $countryCode <fg=green>β</>"); | |
| $regions[$countryCode][$regionCode]['altNames'][] = $regionName; | |
| } | |
| } | |
| } | |
| fclose($handle); | |
| $this->finishProgressBar(); | |
| } | |
| } | |