Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Documentation is available at: https://docs.dotkernel.org/dot-geoip/.
## Badges

![OSS Lifecycle](https://img.shields.io/osslifecycle/dotkernel/dot-geoip)
![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-geoip/3.10.0)
![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-geoip/3.11.0)

[![GitHub issues](https://img.shields.io/github/issues/dotkernel/dot-geoip)](https://github.com/dotkernel/dot-geoip/issues)
[![GitHub forks](https://img.shields.io/github/forks/dotkernel/dot-geoip)](https://github.com/dotkernel/dot-geoip/network)
Expand Down
23 changes: 7 additions & 16 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,26 @@

| Version | Supported | PHP Version |
|---------|--------------------|------------------------------------------------------------------------------------------------------------|
| 3.x | :white_check_mark: | ![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-geoip/3.10.0) |
| 3.x | :white_check_mark: | ![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-geoip/3.11.0) |
| <= 2.x | :x: | |

## Reporting Potential Security Issues

If you have encountered a potential security vulnerability in this project,
please report it to us at <security@dotkernel.com>. We will work with you to
verify the vulnerability and patch it.
If you have encountered a potential security vulnerability in this project, please report it to us at <security@dotkernel.com>.
We will work with you to verify the vulnerability and patch it.

When reporting issues, please provide the following information:

- Component(s) affected
- A description indicating how to reproduce the issue
- A summary of the security vulnerability and impact

We request that you contact us via the email address above and give the
project contributors a chance to resolve the vulnerability and issue a new
release prior to any public exposure; this helps protect the project's
users, and provides them with a chance to upgrade and/or update in order to
protect their applications.

We request that you contact us via the email address above and give the project contributors a chance to resolve the vulnerability and issue a new release prior to any public exposure;
this helps protect the project's users and provides them with a chance to upgrade and/or update to protect their applications.

## Policy

If we verify a reported security vulnerability, our policy is:

- We will patch the current release branch, as well as the immediate prior minor
release branch.

- After patching the release branches, we will immediately issue new security
fix releases for each patched release branch.

- We will patch the current release branch, as well as the immediate prior minor release branch.
- After patching the release branches, we will immediately issue new security fix releases for each patched release branch.
9 changes: 4 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,18 @@
},
"require": {
"php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
"ext-curl": "*",
"ext-zlib": "*",
"dotkernel/dot-cli": "^3.5",
"geoip2/geoip2": "^3.0",
"guzzlehttp/guzzle": "^7.8",
"laminas/laminas-filter": "^2.34",
"psr/container": "^1.1 || ^2.0.0",
"symfony/filesystem": "^7.0"
"psr/container": "^1.1 || ^2.0.0"
},
"require-dev": {
"laminas/laminas-coding-standard": "^3.0",
"mikey179/vfsstream": "^1.6.7",
"phpstan/phpstan": "^2.1",
"phpstan/phpstan-phpunit": "^2.0",
"phpunit/phpunit": "^10.2"
"phpunit/phpunit": "^10.5.59"
},
"autoload": {
"psr-4": {
Expand Down
2 changes: 1 addition & 1 deletion docs/book/v3/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ Dot\GeoIP\ConfigProvider::class,
Register the library's synchronizer command by adding the following line to your application's `config/autoload/cli.global.php` file under the `commands` array key:

```php
Dot\GeoIP\Command\GeoIpCommand::getDefaultName() => Dot\GeoIP\Command\GeoIpCommand::class,
\Dot\GeoIP\Command\GeoIpCommand::$defaultName => \Dot\GeoIP\Command\GeoIpCommand::class,
```
17 changes: 16 additions & 1 deletion docs/book/v3/manage-geolite2-database.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,21 @@ city: n/a -> 2021-07-01 02:09:20
country: n/a -> 2021-07-01 02:05:12
```

Get help for this command by running `php bin/cli.php help geoip:synchronize`.
Get help for this command by running:

```shell
php bin/cli.php geoip:synchronize --help
```

> If you set up the synchronizer command as a cronjob, you can add the `-q|--quiet` option, and it will output data only if an error has occurred.

## Memory limit

By default, the synchronizer command will use up to 128MB of memory.
If it happens to need more memory, you can increase the memory limit by providing the `memory-limit` option when calling the command:

```shell
php bin/cli.php geoip:synchronize --memory-limit 256M
```

You can specify the memory limit in the following formats: `128M`, `1G`, `1024M`, etc.
2 changes: 1 addition & 1 deletion docs/book/v3/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Dotkernel component to provide geographical details about an IP address.
## Badges

![OSS Lifecycle](https://img.shields.io/osslifecycle/dotkernel/dot-geoip)
![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-geoip/3.10.0)
![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-geoip/3.11.0)

[![GitHub issues](https://img.shields.io/github/issues/dotkernel/dot-geoip)](https://github.com/dotkernel/dot-geoip/issues)
[![GitHub forks](https://img.shields.io/github/forks/dotkernel/dot-geoip)](https://github.com/dotkernel/dot-geoip/network)
Expand Down
29 changes: 3 additions & 26 deletions docs/book/v3/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,13 @@
Below is an example implementation of using DotGeoip to retrieve information about an IP address.

```php
<?php

declare(strict_types=1);

namespace Api\Example\Service;

use Dot\GeoIP\Service\LocationServiceInterface;
use Throwable;

/**
* Class ExampleService
* @package Api\Example\Service
*/
class ExampleService
{
protected LocationServiceInterface $locationService;

/**
* ExampleService constructor.
* @param LocationServiceInterface $locationService
*/
public function __construct(LocationServiceInterface $locationService)
{
$this->locationService = $locationService;
public function __construct(
private \Dot\GeoIP\Service\LocationServiceInterface $locationService
) {
}

/**
* @param string $ipAddress
* @return object
*/
public function myMethod(string $ipAddress): object
{
return $this->locationService->getCountry($ipAddress); // Returns an instance of Dot\GeoIP\Data\CountryData
Expand Down
31 changes: 31 additions & 0 deletions src/Client.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Dot\GeoIP;

use function curl_exec;
use function curl_init;
use function curl_setopt_array;
use function fclose;
use function fopen;

use const CURLOPT_FAILONERROR;
use const CURLOPT_FILE;

final readonly class Client
{
public function get(string $url, string $target): void
{
$fp = fopen($target, 'wb');
$ch = curl_init($url);

curl_setopt_array($ch, [
CURLOPT_FILE => $fp,
CURLOPT_FAILONERROR => true,
]);

curl_exec($ch);
fclose($fp);
}
}
63 changes: 41 additions & 22 deletions src/Command/GeoIpCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,27 @@

namespace Dot\GeoIP\Command;

use Dot\GeoIP\Client;
use Dot\GeoIP\Extractor;
use Dot\GeoIP\FileSystem;
use Dot\GeoIP\Service\LocationService;
use Dot\GeoIP\Service\LocationServiceInterface;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\RequestOptions;
use Laminas\Filter\Decompress;
use InvalidArgumentException;
use MaxMind\Db\Reader\Metadata;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Filesystem\Filesystem;

use function array_key_exists;
use function array_keys;
use function date;
use function implode;
use function ini_set;
use function preg_match;
use function sprintf;
use function str_replace;
use function trim;

#[AsCommand(
name: 'geoip:synchronize',
Expand All @@ -35,11 +34,14 @@ class GeoIpCommand extends Command
{
/** @var string $defaultName */
public static $defaultName = 'geoip:synchronize';
private FileSystem $fileSystem;

public function __construct(
protected LocationServiceInterface $locationService,
) {
parent::__construct(self::$defaultName);

$this->fileSystem = new FileSystem();
}

public function configure(): void
Expand All @@ -56,41 +58,44 @@ public function configure(): void
implode(', ', array_keys(LocationService::DATABASES))
),
LocationService::DATABASE_ALL
)
->addOption(
'memory-limit',
'm',
InputOption::VALUE_OPTIONAL,
'Memory limit for decompression. Examples: 256M, 1G',
'128M'
);
}

/**
* @throws GuzzleException
* @throws Exception
*/
public function execute(InputInterface $input, OutputInterface $output): int
{
$fileSystem = new Filesystem();
if (! $fileSystem->exists($this->locationService->getConfig('targetDir'))) {
$fileSystem->mkdir($this->locationService->getConfig('targetDir'));
}
$memoryLimit = $input->getOption('memory-limit');
$this->validateMemoryLimit($memoryLimit);
ini_set('memory_limit', $memoryLimit);

$this->fileSystem->mkdir($this->locationService->getConfig('targetDir'));

$database = $input->getOption('database') ?? LocationService::DATABASE_ALL;
$databases = $this->identifyDatabases($database);
foreach ($databases as $database) {
$sourcePath = $this->locationService->getDatabaseSource($database);
$targetPath = $this->locationService->getDatabasePath($database);
$tempFilePath = $this->locationService->getTempFilePath($database);
$realFilePath = $this->locationService->getRealFilePath($database);

$oldVersion = 'n/a';
$oldMetadata = $this->locationService->getDatabaseMetadata($database);
if ($oldMetadata instanceof Metadata) {
$oldVersion = date('Y-m-d H:i:s', $oldMetadata->buildEpoch);
}

$url = trim($this->locationService->getConfig('databases')[$database]['source']);
$url = str_replace('{year}', date('Y'), $url);
$url = str_replace('{month}', date('m'), $url);
(new Client())->get($url, [RequestOptions::SINK => $sourcePath]);
(new Client())->get($this->locationService->getDatabaseSourceUrl($database), $tempFilePath);

$content = (new Decompress())->getAdapter()->decompress($sourcePath);
$fileSystem->remove($targetPath);
$fileSystem->dumpFile($targetPath, $content);
$fileSystem->remove($sourcePath);
$this->fileSystem->remove($realFilePath);
(new Extractor())->extract($tempFilePath, $realFilePath);
$this->fileSystem->remove($tempFilePath);

$newVersion = 'n/a';
$newMetadata = $this->locationService->getDatabaseMetadata($database);
Expand Down Expand Up @@ -128,4 +133,18 @@ public function identifyDatabases(string $identifier): array

return [$identifier];
}

/**
* @throws InvalidArgumentException
*/
private function validateMemoryLimit(string $memoryLimit): void
{
if (preg_match('/^(\d+)([MG])$/', $memoryLimit) === 1) {
return;
}

throw new InvalidArgumentException(
sprintf('Invalid memory limit: %s', $memoryLimit)
);
}
}
13 changes: 6 additions & 7 deletions src/Data/CityData.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,10 @@

class CityData implements ArraySerializableInterface
{
protected ?string $name;
protected ?string $error;

public function __construct(?string $name = null, ?string $error = null)
{
$this->name = $name;
$this->error = $error;
public function __construct(
private ?string $name = null,
private ?string $error = null,
) {
}

public function getName(): ?string
Expand All @@ -25,6 +22,7 @@ public function getName(): ?string
public function setName(?string $name): self
{
$this->name = $name;

return $this;
}

Expand All @@ -36,6 +34,7 @@ public function getError(): ?string
public function setError(?string $error): self
{
$this->error = $error;

return $this;
}

Expand Down
13 changes: 3 additions & 10 deletions src/Data/ContinentData.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,11 @@

class ContinentData implements ArraySerializableInterface
{
protected ?string $code;
protected ?string $name;
protected ?string $error;

public function __construct(
?string $code = null,
?string $name = null,
?string $error = null
private ?string $code = null,
private ?string $name = null,
private ?string $error = null,
) {
$this->code = $code;
$this->name = $name;
$this->error = $error;
}

public function getCode(): ?string
Expand Down
17 changes: 4 additions & 13 deletions src/Data/CountryData.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,12 @@

class CountryData implements ArraySerializableInterface
{
protected ?bool $isEuMember;
protected ?string $isoCode;
protected ?string $name;
protected ?string $error;

public function __construct(
?bool $isEuMember = false,
?string $isoCode = null,
?string $name = null,
?string $error = null
private ?bool $isEuMember = false,
private ?string $isoCode = null,
private ?string $name = null,
private ?string $error = null,
) {
$this->isEuMember = $isEuMember;
$this->isoCode = $isoCode;
$this->name = $name;
$this->error = $error;
}

public function getIsEuMember(): ?bool
Expand Down
Loading