PHPackages                             rumenx/php-geolocation - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. rumenx/php-geolocation

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

rumenx/php-geolocation
======================

Framework-agnostic PHP utility for CloudFlare geolocation detection with multi-language support and local development simulation.

v1.0.2(7mo ago)41.7k↓31.3%[1 issues](https://github.com/RumenDamyanov/php-geolocation/issues)MITPHPPHP ^8.2CI passing

Since Jun 18Pushed 1mo agoCompare

[ Source](https://github.com/RumenDamyanov/php-geolocation)[ Packagist](https://packagist.org/packages/rumenx/php-geolocation)[ Docs](https://github.com/RumenDamyanov/php-geolocation)[ GitHub Sponsors](https://github.com/sponsors/RumenDamyanov)[ RSS](/packages/rumenx-php-geolocation/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (2)Dependencies (3)Versions (7)Used By (0)

php-geolocation
===============

[](#php-geolocation)

[![CI](https://github.com/RumenDamyanov/php-geolocation/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/RumenDamyanov/php-geolocation/actions/workflows/ci.yml)[![Analyze](https://github.com/RumenDamyanov/php-geolocation/actions/workflows/analyze.yml/badge.svg?branch=master)](https://github.com/RumenDamyanov/php-geolocation/actions/workflows/analyze.yml)[![Style](https://github.com/RumenDamyanov/php-geolocation/actions/workflows/style.yml/badge.svg?branch=master)](https://github.com/RumenDamyanov/php-geolocation/actions/workflows/style.yml)[![codecov](https://camo.githubusercontent.com/d14669a1af81433b2f8897e9706cf78942147efebe9b6d10b4cf38a4fac72820/68747470733a2f2f636f6465636f762e696f2f67682f52756d656e44616d79616e6f762f7068702d67656f6c6f636174696f6e2f6272616e63682f6d61737465722f67726170682f62616467652e737667)](https://codecov.io/gh/RumenDamyanov/php-geolocation)

A simple, framework-agnostic PHP utility for Cloudflare geolocation detection and client information extraction. Provides helpers to access geolocation, language, and client information (OS, browser, device, resolution) from HTTP headers.

Features
--------

[](#features)

- 🌍 Detects Cloudflare geolocation headers (country, IP, etc.)
- 🔍 Helper methods to access geolocation, language, and client info (OS, browser, device, resolution)
- 🌐 Configurable country-to-language mapping (supports multiple official languages per country)
- 🤝 Language negotiation: matches browser and available site languages for multi-language countries
- 🍪 Configurable language cookie name
- ⚙️ Configurable fields for returned visitor info
- 🛠️ **Local development simulation** - Fake Cloudflare headers for testing without production setup
- 🎭 **Auto-detection** of local environments (localhost, local IPs, missing Cloudflare headers)
- 🧪 Fully tested with Pest (100% coverage)
- ✅ PSR-12 compliant, static analysis and style checks
- 🚀 Simple utility class - no framework dependencies or complex setup required

📚 Documentation &amp; Wiki
--------------------------

[](#-documentation--wiki)

For comprehensive documentation, examples, and advanced usage patterns, visit our **[Complete Wiki Documentation](https://github.com/RumenDamyanov/php-geolocation/wiki)**:

### 🚀 Quick Links

[](#-quick-links)

- **[Quick Start Guide](https://github.com/RumenDamyanov/php-geolocation/wiki/quick-start)** - Get running in minutes
- **[Framework Integration](https://github.com/RumenDamyanov/php-geolocation/wiki/laravel-integration)** - Laravel, Symfony, CodeIgniter guides
- **[CloudFlare Setup](https://github.com/RumenDamyanov/php-geolocation/wiki/cloudflare-setup)** - Production configuration
- **[Local Development](https://github.com/RumenDamyanov/php-geolocation/wiki/simulation)** - Testing without CloudFlare
- **[Multi-language Websites](https://github.com/RumenDamyanov/php-geolocation/wiki/multilang-websites)** - International applications
- **[Production Deployment](https://github.com/RumenDamyanov/php-geolocation/wiki/production)** - Best practices &amp; monitoring
- **[API Development](https://github.com/RumenDamyanov/php-geolocation/wiki/api-patterns)** - RESTful APIs with geolocation
- **[Configuration Reference](https://github.com/RumenDamyanov/php-geolocation/wiki/config-reference)** - Complete options guide

### 📖 Advanced Topics

[](#-advanced-topics)

- **[Error Handling](https://github.com/RumenDamyanov/php-geolocation/wiki/error-handling)** - Robust error management
- **[Caching Strategies](https://github.com/RumenDamyanov/php-geolocation/wiki/caching)** - Performance optimization
- **[Analytics Integration](https://github.com/RumenDamyanov/php-geolocation/wiki/analytics)** - Geographic tracking
- **[Troubleshooting](https://github.com/RumenDamyanov/php-geolocation/wiki/troubleshooting)** - Common issues &amp; solutions

Why This Design?
----------------

[](#why-this-design)

This package is intentionally designed as a **simple utility library** rather than a complex framework integration. Here's why:

### 🎯 Focused Purpose

[](#-focused-purpose)

- **Single responsibility**: Extract and process geolocation data from HTTP headers
- **Pure functions**: No side effects, no global state, predictable behavior
- **Framework-agnostic**: Works with any PHP application or framework

### 🔧 Easy Integration

[](#-easy-integration)

- **No service providers needed**: Just instantiate the class when you need it
- **No configuration files**: Pass configuration directly to the constructor
- **No middleware complexity**: Use it exactly where and when you need it
- **Developer control**: You decide how and when to use geolocation data

### 📦 Minimal Dependencies

[](#-minimal-dependencies)

- **Zero runtime dependencies**: Only requires PHP 8.3+
- **Small footprint**: Single class, focused functionality
- **Fast installation**: No complex dependency trees
- **Version compatibility**: No framework version constraints

This approach makes the package more reliable, easier to understand, and simpler to maintain - following the Unix philosophy of "do one thing and do it well."

Installation
------------

[](#installation)

```
composer require rumenx/php-geolocation
```

Local Development Simulation
----------------------------

[](#local-development-simulation)

When developing locally where Cloudflare is not available, you can simulate its functionality:

### Quick Simulation

[](#quick-simulation)

```
use Rumenx\Geolocation\Geolocation;

// Create a simulated instance for a specific country
$geo = Geolocation::simulate('DE', [
    'DE' => ['de'],
    'CA' => ['en', 'fr']
]);

echo $geo->getCountryCode(); // 'DE'
echo $geo->getIp(); // Simulated IP like '192.168.4.123'
```

### Advanced Simulation

[](#advanced-simulation)

```
use Rumenx\Geolocation\GeolocationSimulator;

// Generate fake Cloudflare headers
$headers = GeolocationSimulator::fakeCloudflareHeaders('JP', [
    'user_agent' => 'Custom User Agent',
    'server_name' => 'dev.example.com'
]);

// Create instance with simulated server data
$geo = new Geolocation($headers, ['JP' => ['ja', 'en']]);
```

### Auto-Detection of Local Environment

[](#auto-detection-of-local-environment)

```
$geo = new Geolocation();

if ($geo->isLocalDevelopment()) {
    // Automatically detected: localhost, local IPs, or missing Cloudflare headers
    echo "Running in local development mode";
}
```

### Available Countries for Simulation

[](#available-countries-for-simulation)

```
// Get list of built-in countries
$countries = GeolocationSimulator::getAvailableCountries();
// ['US', 'CA', 'GB', 'DE', 'FR', 'JP', 'AU', 'BR']

// Get random country for testing
$randomCountry = GeolocationSimulator::randomCountry();
```

### Framework Integration for Development

[](#framework-integration-for-development)

For Laravel and Symfony, check the `/examples` directory for middleware and event listeners that automatically inject simulated Cloudflare headers in development environments.

Usage
-----

[](#usage)

### Basic Usage

[](#basic-usage)

```
use Rumenx\Geolocation\Geolocation;

// Simple usage with defaults
$geo = new Geolocation();
$country = $geo->getCountryCode();
$ip = $geo->getIp();
$info = $geo->getGeoInfo();

// Advanced usage with custom configuration
$countryToLanguage = [
    'CA' => ['en', 'fr'], // Canada: English (default), French
    'DE' => ['de'],       // Germany: German
    'CH' => ['de', 'fr', 'it'], // Switzerland: German, French, Italian
    // Add more countries as needed...
];

$geo = new Geolocation(
    $_SERVER,                // HTTP server array (optional, defaults to $_SERVER)
    $countryToLanguage,      // Country-to-language mapping (optional)
    'my_lang_cookie'         // Custom cookie name (optional, defaults to 'lang')
);
```

### Language Detection

[](#language-detection)

```
// Get best language for visitor based on country and browser preferences
$availableSiteLanguages = ['en', 'fr', 'de', 'es'];
$lang = $geo->getLanguageForCountry(null, $availableSiteLanguages);

// Language selection logic:
// 1. If browser preferred language matches a country language and is available, use it
// 2. Else, check all browser languages for a match with available languages
// 3. Else, use the first country language as fallback
// 4. Returns null if no match found

// Check if language should be set (based on cookie)
if ($geo->shouldSetLanguage()) {
    // Set language in your application
    setcookie($geo->languageCookieName, $lang);
}
```

### Client Information

[](#client-information)

```
// Get specific information
$country = $geo->getCountryCode();     // 'US', 'CA', 'DE', etc.
$ip = $geo->getIp();                   // '192.168.1.1'
$browser = $geo->getBrowser();         // ['name' => 'Chrome', 'version' => '91.0']
$os = $geo->getOs();                   // 'Windows 10', 'macOS', 'Linux', etc.
$device = $geo->getDeviceType();       // 'desktop', 'mobile', 'tablet'
$resolution = $geo->getResolution();   // ['width' => 1920, 'height' => 1080]

// Get all information at once
$info = $geo->getGeoInfo();
// Returns: [
//     'country_code' => 'US',
//     'ip' => '192.168.1.1',
//     'preferred_language' => 'en-US',
//     'all_languages' => ['en-US', 'en', 'fr'],
//     'user_agent' => 'Mozilla/5.0...',
//     'browser' => ['name' => 'Chrome', 'version' => '91.0'],
//     'os' => 'Windows 10',
//     'device_type' => 'desktop',
//     'resolution' => ['width' => 1920, 'height' => 1080]
// ]

// Get only specific fields
$specificInfo = $geo->getGeoInfo(['country_code', 'ip', 'browser']);
```

### Framework Integration Examples

[](#framework-integration-examples)

#### Laravel

[](#laravel)

```
// In a controller
class HomeController extends Controller
{
    public function index(Request $request)
    {
        $geo = new Geolocation(
            $request->server->all(),
            config('app.country_to_language', [])
        );

        $country = $geo->getCountryCode();
        $lang = $geo->getLanguageForCountry(null, ['en', 'fr', 'de']);

        if ($geo->shouldSetLanguage() && $lang) {
            app()->setLocale($lang);
        }

        return view('home', [
            'geo' => $geo->getGeoInfo(['country_code', 'ip']),
            'language' => $lang
        ]);
    }
}

// In a middleware (optional)
class GeolocationMiddleware
{
    public function handle($request, Closure $next)
    {
        $geo = new Geolocation($request->server->all());
        $lang = $geo->getLanguageForCountry();

        if ($lang && $geo->shouldSetLanguage()) {
            app()->setLocale($lang);
        }

        return $next($request);
    }
}
```

#### Symfony

[](#symfony)

```
// In a controller
class HomeController extends AbstractController
{
    public function index(Request $request): Response
    {
        $geo = new Geolocation(
            $request->server->all(),
            $this->getParameter('country_to_language')
        );

        $country = $geo->getCountryCode();
        $lang = $geo->getLanguageForCountry(null, ['en', 'fr', 'de']);

        if ($geo->shouldSetLanguage() && $lang) {
            $request->setLocale($lang);
        }

        return $this->render('home.html.twig', [
            'geo' => $geo->getGeoInfo(),
            'language' => $lang
        ]);
    }
}

// In an event listener (optional)
class GeolocationListener
{
    public function onKernelRequest(RequestEvent $event): void
    {
        $request = $event->getRequest();
        $geo = new Geolocation($request->server->all());
        $lang = $geo->getLanguageForCountry();

        if ($lang && $geo->shouldSetLanguage()) {
            $request->setLocale($lang);
        }
    }
}
```

#### Plain PHP

[](#plain-php)

```
// In any PHP application
session_start();

$geo = new Geolocation($_SERVER, [
    'US' => ['en'],
    'CA' => ['en', 'fr'],
    'DE' => ['de'],
    'FR' => ['fr']
]);

$country = $geo->getCountryCode();
$lang = $geo->getLanguageForCountry(null, ['en', 'fr', 'de']);

// Set language preference
if ($geo->shouldSetLanguage() && $lang) {
    $_SESSION['language'] = $lang;
    setcookie('lang', $lang, time() + (86400 * 30)); // 30 days
}

// Use the information
echo "Welcome visitor from: " . ($country ?? 'Unknown');
echo "Preferred language: " . ($lang ?? 'Default');
```

Configuration
-------------

[](#configuration)

The package is simple and requires minimal configuration. All settings are passed directly to the constructor:

### Constructor Parameters

[](#constructor-parameters)

```
$geo = new Geolocation($server, $countryToLanguage, $languageCookieName);
```

- **`$server`** (array, optional): HTTP server array, defaults to `$_SERVER`
- **`$countryToLanguage`** (array, optional): Country code to language mapping
- **`$languageCookieName`** (string, optional): Language cookie name, defaults to `'lang'`

### Country-to-Language Mapping

[](#country-to-language-mapping)

Map country codes (ISO 3166-1 alpha-2) to language codes or arrays. The first language is the default for the country:

```
$countryToLanguage = [
    'US' => ['en'],                    // United States: English only
    'CA' => ['en', 'fr'],              // Canada: English (default), French
    'CH' => ['de', 'fr', 'it', 'rm'],  // Switzerland: German (default), French, Italian, Romansh
    'BE' => ['nl', 'fr', 'de'],        // Belgium: Dutch (default), French, German
    'IN' => ['hi', 'en'],              // India: Hindi (default), English
    'ZA' => ['en', 'af', 'zu'],        // South Africa: English (default), Afrikaans, Zulu
    // Add more countries as needed...
];
```

### Example Configurations

[](#example-configurations)

#### Minimal Setup

[](#minimal-setup)

```
// Use defaults for everything
$geo = new Geolocation();
```

#### Basic Country Mapping

[](#basic-country-mapping)

```
$geo = new Geolocation($_SERVER, [
    'DE' => ['de'],
    'FR' => ['fr'],
    'ES' => ['es']
]);
```

#### Custom Cookie Name

[](#custom-cookie-name)

```
$geo = new Geolocation($_SERVER, [], 'user_language');
```

#### Full Configuration

[](#full-configuration)

```
$geo = new Geolocation(
    $_SERVER,  // or $request->server->all() in frameworks
    [
        'US' => ['en'],
        'CA' => ['en', 'fr'],
        'MX' => ['es'],
        'DE' => ['de'],
        'AT' => ['de'],
        'CH' => ['de', 'fr', 'it'],
        'FR' => ['fr'],
        'BE' => ['nl', 'fr'],
        'IT' => ['it'],
        'ES' => ['es'],
        'BR' => ['pt'],
        'PT' => ['pt'],
        'RU' => ['ru'],
        'CN' => ['zh'],
        'JP' => ['ja'],
        'KR' => ['ko']
    ],
    'preferred_language'
);
```

No configuration files, service providers, or complex setup needed!

Examples
--------

[](#examples)

The [`examples/`](examples/) directory contains practical demonstrations of the package capabilities:

### 🎯 Basic Usage

[](#-basic-usage)

- **[`demo.php`](examples/demo.php)** - Interactive demo showing simulation in local development with multiple countries

### ⚡ Framework Integration

[](#-framework-integration)

- **[`LaravelDevelopmentMiddleware.php`](examples/LaravelDevelopmentMiddleware.php)** - Laravel middleware for automatic header injection in development
- **[`SymfonyDevelopmentListener.php`](examples/SymfonyDevelopmentListener.php)** - Symfony event listener for request-level simulation

### 🌍 Real-World Applications

[](#-real-world-applications)

- **[`content-localization.php`](examples/content-localization.php)** - Redirect visitors to country-specific domains
- **[`api-endpoint.php`](examples/api-endpoint.php)** - REST API with geolocation-based responses (currency, features, etc.)
- **[`multi-language.php`](examples/multi-language.php)** - Automatic language detection with fallbacks for multi-language sites

### Running Examples

[](#running-examples)

```
# Basic simulation demo
php examples/demo.php

# Content localization
php examples/content-localization.php

# API endpoint simulation
php examples/api-endpoint.php

# Multi-language detection
php examples/multi-language.php
```

All examples automatically detect local development and use simulation, so they work perfectly without Cloudflare setup! 🚀

Contributing
------------

[](#contributing)

We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details on how to contribute to this project.

### Code of Conduct

[](#code-of-conduct)

This project adheres to a [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to the project maintainers.

### Development

[](#development)

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Run tests: `composer test`
5. Run static analysis: `composer analyze`
6. Check code style: `composer style`
7. Submit a pull request

Related Projects
----------------

[](#related-projects)

### 🐹 Go Version

[](#-go-version)

- **[go-geolocation](https://github.com/RumenDamyanov/go-geolocation)** - Go adaptation of this package with similar functionality for the Go ecosystem

### 🔮 Future Versions (Planned)

[](#-future-versions-planned)

- **Python version** - Python adaptation planned for future release
- **WordPress plugin** - WordPress integration plugin planned
- **Drupal module** - Drupal integration module planned

Security
--------

[](#security)

If you discover a security vulnerability, please see our [Security Policy](SECURITY.md) for information on how to report it responsibly.

Changelog
---------

[](#changelog)

All notable changes to this project are documented in the [Changelog](CHANGELOG.md).

Support
-------

[](#support)

- 📖 [Documentation](README.md)
- 🐛 [Issue Tracker](https://github.com/RumenDamyanov/php-geolocation/issues)
- 💬 [Discussions](https://github.com/RumenDamyanov/php-geolocation/discussions)
- 💖 [Sponsor this project](FUNDING.md)

License
-------

[](#license)

[MIT](LICENSE.md)

###  Health Score

42

—

FairBetter than 90% of packages

Maintenance72

Regular maintenance activity

Popularity24

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 59.7% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~48 days

Total

3

Last Release

237d ago

PHP version history (2 changes)v1.0.1PHP ^8.3

v1.0.2PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/48dce3e6200e787e75a4a14e0d31738d112261fe0877f15f74d3fb2c2a626229?d=identicon)[RumenX](/maintainers/RumenX)

---

Top Contributors

[![RumenDamyanov](https://avatars.githubusercontent.com/u/1458253?v=4)](https://github.com/RumenDamyanov "RumenDamyanov (40 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (27 commits)")

---

Tags

cloudflaregeolocationlaravelphpsymfonyphplanguageutilitygeolocationSimpleIPcloudflarecountryframework agnostic

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/rumenx-php-geolocation/health.svg)

```
[![Health](https://phpackages.com/badges/rumenx-php-geolocation/health.svg)](https://phpackages.com/packages/rumenx-php-geolocation)
```

###  Alternatives

[zakirullin/mess

Convenient array-related routine &amp; better type casting

21228.9k2](/packages/zakirullin-mess)[fab2s/souuid

Simple Ordered Uuid Generator in PHP

13573.2k1](/packages/fab2s-souuid)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
