Skip to content

Commit

Permalink
feat: replaced unknown API calls with official MaxMind endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
danielsreichenbach committed May 2, 2024
1 parent 2838d29 commit b3d23e6
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 110 deletions.
5 changes: 4 additions & 1 deletion .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:

1. Updating via Composer or from a php application?
2. Which editions of the databases you are trying to update?
3. What configuration settings are you using? (here you can replace the license key "maxmind" with "...").
Expand All @@ -23,9 +24,11 @@ Steps to reproduce the behavior:
If applicable, add screenshots to help explain your problem.

**Environment (please complete the following information):**

- OS: [e.g. Windows or Linux or other]
- PHP version: [e.g. 5.3.0, 7.4.0]
- `tronovav/geoip2-update` version (to check the version run the command `composer show tronovav/geoip2-update`): [e.g. v2.1.11]
- `danielsreichenbach/geoip2-update` version (to check the version run the
command `composer show danielsreichenbach/geoip2-update`): [e.g. v2.1.11]
- Composer version: [e.g. 2.0.13]

**Additional context**
Expand Down
53 changes: 29 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,46 +1,51 @@
[![Geoip2 Update](https://user-images.githubusercontent.com/25905384/111375423-4631ce00-86af-11eb-81a9-2bc4dab89068.png)](https://www.geodbase-update.com/?utm_source=github&utm_medium=organic&utm_campaign=github_project_page&utm_content=main_banner)
# geoip2-update

Geoip2 Update is a PHP tool for updating Maxmind GeoLite2 and GeoIP2 databases from your script, application or via Composer.
[![Geoip2 Update](https://user-images.githubusercontent.com/25905384/111375423-4631ce00-86af-11eb-81a9-2bc4dab89068.png)](https://www.geodbase-update.com/?utm_source=github&utm_medium=organic&utm_campaign=github_project_page&utm_content=main_banner)

[![Latest Stable Version](https://img.shields.io/packagist/v/tronovav/geoip2-update)](https://packagist.org/packages/tronovav/geoip2-update)
[![GitHub downloads](https://img.shields.io/packagist/dt/tronovav/geoip2-update)](https://packagist.org/packages/tronovav/geoip2-update)
Geoip2 Update is a PHP tool for updating Maxmind GeoLite2 and GeoIP2 databases
from your script, application or via Composer.

[![Payeer](https://payeer.com/style/images/banner/970x90-1.jpg)](https://payeer.com/031702636)
[![Latest Stable Version](https://img.shields.io/packagist/v/danielsreichenbach/geoip2-update)](https://packagist.org/packages/danielsreichenbach/geoip2-update)
[![GitHub downloads](https://img.shields.io/packagist/dt/danielsreichenbach/geoip2-update)](https://packagist.org/packages/danielsreichenbach/geoip2-update)

INSTALLATION
------------
## INSTALLATION

```bash
composer require tronovav/geoip2-update
composer require danielsreichenbach/geoip2-update
```

DOCUMENTATION
-------------
## DOCUMENTATION

You can read the documentation on setting up and using the library, as well as learn about new features on the official website.
You can read the documentation on setting up and using the library, as well as
learn about new features on the official website.

**Go to documentation -> [GeoIP2 Update Documentation](https://www.geodbase-update.com/?utm_source=github&utm_medium=organic&utm_campaign=github_project_page&utm_content=documentation_link)**

FEATURES
--------
## FEATURES

### 1. Updating GeoIP2 databases via Composer

To update Geoip2 databases via Composer, you can set up an update call in your
`composer.json`.

### 1. Updating GeoIP2 databases via Composer.
Each time the `composer update` command is invoked, the library will check for
updates on the "maxmind.com" server and update the Geoip2 databases if
necessary.

To update Geoip2 databases via Composer, you can set up an update call in your `composer.json`.
Each time the `composer update` command is invoked, the library will check for updates on the "maxmind.com" server and update the Geoip2 databases if necessary.
You can also update only `GeoIP2` databases without updating all project dependencies:
`composer update tronovav/geoip2-update`.
You can also update only `GeoIP2` databases without updating all project
dependencies: `composer update danielsreichenbach/geoip2-update`.

### 2. Updating GeoIP2 databases from your PHP application.
### 2. Updating GeoIP2 databases from your PHP application

You can use this option to update `GeoIP2` databases from your PHP project, or use `Cron` on Linux, or use `Task Scheduler` on Windows.
You can use this option to update `GeoIP2` databases from your PHP project, or
use `cron` on Linux, or use `Task Scheduler` on Windows.

### 3. Simple, cross-platform and reliable.
### 3. Simple, cross-platform and reliable

Does not depend on the operating system and can be used on hosting services and production servers.
Does not depend on the operating system and can be used on hosting services and
production servers.

COPYRIGHT AND LICENSE
---------------------
## COPYRIGHT AND LICENSE

This software is Copyright (c) 2021 by Andrey Tronov.

Expand Down
17 changes: 13 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "tronovav/geoip2-update",
"name": "danielsreichenbach/geoip2-update",
"description": "Update GeoIP2/GeoLite2 databases from your script, program or via composer.",
"keywords": [
"geoip",
Expand All @@ -14,22 +14,31 @@
{
"name": "Andrey Tronov",
"email": "[email protected]"
},
{
"name": "Daniel S. Reichenbach",
"email": "[email protected]"
}
],
"support": {
"email": "[email protected]"
},
"require": {
"php": ">=5.3",
"php": ">=8.0",
"ext-curl": "*",
"ext-json": "*"
"ext-json": "*",
"composer-plugin-api": "^2.1"
},
"suggest": {
"ext-zip": "Required for updating the CSV databases."
},
"autoload": {
"psr-4": {
"tronovav\\GeoIP2Update\\": "src/"
"danielsreichenbach\\GeoIP2Update\\": "src/"
}
},
"require-dev": {
"composer/composer": "^2.1",
"symfony/console": "^7.0"
}
}
110 changes: 47 additions & 63 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,16 @@ class Client
const ARCHIVE_ZIP = 'zip';

/**
* @var string Your account’s actual license key on www.maxmind.com
* @var string Your account’s unique id on www.maxmind.com
* @link https://support.maxmind.com/account-faq/license-keys/where-do-i-find-my-license-key/
*/
public $license_key;
public $account_id;

/**
* @var string Your account’s actual "geodbase_update_key" on www.geodbase-update.com
* @link https://www.geodbase-update.com
* @var string Your account’s actual license key on www.maxmind.com
* @link https://support.maxmind.com/account-faq/license-keys/where-do-i-find-my-license-key/
*/
public $geodbase_update_key;
public $license_key;

/**
* @var string[] Database editions list to update.
Expand All @@ -47,7 +47,7 @@ class Client
public $dir;

protected $_editionVersions = array();
protected $_baseUrlApi = 'https://www.geodbase-update.com/api/v1/edition';
protected $_baseUrlApi = 'https://updates.maxmind.com';
protected $_updated = array();
protected $_errors = array();
protected $_errorUpdateEditions = array();
Expand Down Expand Up @@ -102,7 +102,7 @@ public function run()
protected function setConfParams(&$params)
{
if (array_key_exists('geoipConfFile', $params)) {
if(is_file($params['geoipConfFile']) && is_readable($params['geoipConfFile'])) {
if (is_file($params['geoipConfFile']) && is_readable($params['geoipConfFile'])) {
$confParams = array();
foreach (file($params['geoipConfFile']) as $line) {
$confString = trim($line);
Expand All @@ -114,11 +114,11 @@ protected function setConfParams(&$params)
: trim($matches['value']);
}
}
$this->account_id = !empty($confParams['AccountId']) ? $confParams['AccountId'] : $this->account_id;
$this->license_key = !empty($confParams['LicenseKey']) ? $confParams['LicenseKey'] : $this->license_key;
$this->editions = !empty($confParams['EditionIDs']) ? $confParams['EditionIDs'] : $this->editions;
}
else{
$this->_errors[] = 'The geoipConfFile parameter was specified, but the file itself is missing or unreadable. See https://www.geodbase-update.com';
} else {
$this->_errors[] = 'The geoipConfFile parameter was specified, but the file itself is missing or unreadable.';
}
unset($params['geoipConfFile']);
}
Expand All @@ -134,20 +134,23 @@ protected function validate()

switch (true) {
case empty($this->dir):
$this->_errors[] = 'Destination directory not specified. See documentation at https://www.geodbase-update.com';
$this->_errors[] = 'Destination directory not specified.';
break;
case !is_dir($this->dir):
$this->_errors[] = "The destination directory \"{$this->dir}\" does not exist. See documentation at https://www.geodbase-update.com";
$this->_errors[] = "The destination directory \"{$this->dir}\" does not exist.";
break;
case !is_writable($this->dir):
$this->_errors[] = "The destination directory \"{$this->dir}\" is not writable. See documentation at https://www.geodbase-update.com";
$this->_errors[] = "The destination directory \"{$this->dir}\" is not writable.";
}

if (empty($this->account_id))
$this->_errors[] = 'You must specify your Maxmind "account_id".';

if (empty($this->license_key))
$this->_errors[] = 'You must specify your Maxmind "license_key". See documentation at https://www.geodbase-update.com';
$this->_errors[] = 'You must specify your Maxmind "license_key".';

if (empty($this->editions))
$this->_errors[] = "No GeoIP revision names are specified for the update. See documentation at https://www.geodbase-update.com";
$this->_errors[] = "No GeoIP revision names are specified for the update.";

if (!empty($this->_errors))
return false;
Expand All @@ -166,21 +169,16 @@ protected function updateEdition($editionId)
if (!empty($this->_errorUpdateEditions[$editionId]))
return;

if ($remoteEditionData['ext'] === self::ARCHIVE_ZIP && !class_exists('\ZipArchive')) {
$this->_errorUpdateEditions[$editionId] = "PHP zip extension is required to update csv databases. See https://www.php.net/manual/en/zip.installation.php to install zip php extension.";
return;
}

$remoteActualVersion = date_create($remoteEditionData['version']);
$remoteActualVersion = date_create($remoteEditionData['date']);

$localEditionData = is_file($this->getEditionDirectory($editionId) . DIRECTORY_SEPARATOR . $this->_lastModifiedStorageFileName) ?
file_get_contents($this->getEditionDirectory($editionId) . DIRECTORY_SEPARATOR . $this->_lastModifiedStorageFileName) : '';

$currentVersion = date_create_from_format('Y-m-d\TH:i:sP',$localEditionData) ?: 0;
$currentVersion = date_create_from_format('Y-m-d', $localEditionData) ?: 0;

$this->_editionVersions[$editionId] = array(!empty($currentVersion) ? $currentVersion->format('c') : 0,$remoteActualVersion->format('c'));
$this->_editionVersions[$editionId] = array(!empty($currentVersion) ? $currentVersion->format('Ymd') : 0, $remoteActualVersion->format('Ymd'));

if (empty($currentVersion) || $currentVersion != $remoteActualVersion) {
if (empty($currentVersion) || $currentVersion < $remoteActualVersion) {

$this->download($remoteEditionData);
if (!empty($this->_errorUpdateEditions[$editionId]))
Expand Down Expand Up @@ -210,49 +208,46 @@ protected function getEditionDirectory($editionId)
*/
protected function getRemoteEditionData($editionId)
{
$ch = curl_init(trim($this->_baseUrlApi,'/').'/'.'data'.'?'. http_build_query(array(
'id' => $editionId,
)));
$ch = curl_init(trim($this->_baseUrlApi, '/') . '/' . 'geoip/updates/metadata' . '?' . http_build_query([
'edition_id' => $editionId,
]));
curl_setopt_array($ch, array(
CURLOPT_HEADER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json',
'Accept: application/json',
'X-Api-Key: '.$this->geodbase_update_key,
),
CURLOPT_POSTFIELDS => json_encode(array(
'maxmind_key' =>$this->license_key,
'client' => $this->_client,
'client_version' => $this->_client_version,
)),
CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
CURLOPT_USERPWD => sprintf("%s:%s", $this->account_id, $this->license_key),
));

$result = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if(empty($httpCode)){
if (empty($httpCode)) {
$this->_errorUpdateEditions[$editionId] = "The remote server is not available.";
return array();
}

$resultArray = json_decode($result,true);
$resultArray = json_decode($result, true);

if($httpCode !== 200){
$this->_errorUpdateEditions[$editionId] = $resultArray['data']['message'] ?: $resultArray['data']['name'];
if ($httpCode !== 200) {
$this->_errorUpdateEditions[$editionId] = $resultArray['error'] ?: $resultArray['error'];
return array();
}
return $resultArray['data'];

return $resultArray['databases'][0];
}

/**
* @param array $remoteEditionData
*/
protected function download($remoteEditionData)
{
$ch = curl_init(trim($this->_baseUrlApi,'/').'/'.'download'.'?'. http_build_query(array(
$ch = curl_init(trim($this->_baseUrlApi, '/') . '/' . 'download' . '?' . http_build_query(array(
'request_id' => $remoteEditionData['request_id'],
)));
$fh = fopen($this->getArchiveFile($remoteEditionData), 'wb');
Expand All @@ -261,60 +256,49 @@ protected function download($remoteEditionData)
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json',
'X-Api-Key: '.$this->geodbase_update_key,
),
CURLOPT_FILE => $fh,
CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
CURLOPT_USERPWD => sprintf("%s:%s", $this->account_id, $this->license_key),
));
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
fclose($fh);
if ($response === false || $httpCode !== 200){
if(is_file($this->getArchiveFile($remoteEditionData)))
if ($response === false || $httpCode !== 200) {
if (is_file($this->getArchiveFile($remoteEditionData)))
unlink($this->getArchiveFile($remoteEditionData));
$this->_errorUpdateEditions[$remoteEditionData['id']] = "Download error: ($httpCode)" . curl_error($ch);
}
}

protected function getArchiveFile($remoteEditionData)
{
return $this->dir . DIRECTORY_SEPARATOR . $remoteEditionData['id'] . '.' . $remoteEditionData['ext'];
return $this->dir . DIRECTORY_SEPARATOR . $remoteEditionData['edition_id'] . '.' . 'tar.gz';
}

/**
* @param array $remoteEditionData
*/
protected function extract($remoteEditionData)
{
switch ($remoteEditionData['ext']) {
case self::ARCHIVE_GZ:

$phar = new \PharData($this->getArchiveFile($remoteEditionData));
$phar->extractTo($this->dir, null, true);
break;
case self::ARCHIVE_ZIP:

$zip = new \ZipArchive;
$zip->open($this->getArchiveFile($remoteEditionData));
$zip->extractTo($this->dir);
$zip->close();
break;
}
$phar = new \PharData($this->getArchiveFile($remoteEditionData));
$phar->extractTo($this->dir, null, true);

unlink($this->getArchiveFile($remoteEditionData));

if (!is_dir($this->getEditionDirectory($remoteEditionData['id'])))
mkdir($this->getEditionDirectory($remoteEditionData['id']));
if (!is_dir($this->getEditionDirectory($remoteEditionData['edition_id'])))
mkdir($this->getEditionDirectory($remoteEditionData['edition_id']));

$directories = new \DirectoryIterator($this->dir);
foreach ($directories as $directory)
/* @var \DirectoryIterator $directory */
if ($directory->isDir() && preg_match('/^' . $remoteEditionData['id'] . '[_\d]+$/i', $directory->getBasename())) {
if ($directory->isDir() && preg_match('/^' . $remoteEditionData['edition_id'] . '[_\d]+$/i', $directory->getBasename())) {
$newEditionDirectory = new \DirectoryIterator($directory->getPathname());
foreach ($newEditionDirectory as $item)
if ($item->isFile())
rename($item->getPathname(), $this->getEditionDirectory($remoteEditionData['id']) . DIRECTORY_SEPARATOR . $item->getBasename());
file_put_contents($this->getEditionDirectory($remoteEditionData['id']) . DIRECTORY_SEPARATOR . $this->_lastModifiedStorageFileName, $remoteEditionData['version']);
rename($item->getPathname(), $this->getEditionDirectory($remoteEditionData['edition_id']) . DIRECTORY_SEPARATOR . $item->getBasename());
file_put_contents($this->getEditionDirectory($remoteEditionData['edition_id']) . DIRECTORY_SEPARATOR . $this->_lastModifiedStorageFileName, $remoteEditionData['date']);
$this->deleteDirectory($directory->getPathname());
break;
}
Expand Down
Loading

0 comments on commit b3d23e6

Please sign in to comment.