gryfoss/http-cf-geolocation-service
最新稳定版本:v1.1.0
Composer 安装命令:
composer require gryfoss/http-cf-geolocation-service
包简介
Wrapper around GeoIP service and CloudFlare functionality which grants ISO code of the detected country during masking of IPs.
README 文档
README
A high-performance PHP service for detecting user geolocation using Cloudflare headers with MaxMind GeoIP database fallback.
🎯 Purpose
CFGeolocationService is designed to provide fast and accurate geolocation detection by leveraging Cloudflare's edge network capabilities while maintaining reliability through GeoIP database fallbacks. This dual-strategy approach ensures optimal performance and accuracy for web applications behind Cloudflare's proxy network.
Key Benefits
- 🚀 Performance: Prioritizes Cloudflare headers for instant geolocation (no database lookup required)
- 🛡️ Reliability: Falls back to MaxMind GeoIP2 database when Cloudflare headers are unavailable
- 🌐 Accuracy: Uses Cloudflare's global edge network data combined with MaxMind's proven database
- ⚡ Speed: Minimal overhead with intelligent caching strategy
- 🔒 Security: Validates all inputs and handles edge cases gracefully
🏗️ How It Works
1. Check CF-IPCountry header → Valid ISO country code? → Return country
↓
2. Check CF-Connecting-IP header → Valid IP address? → Use for GeoIP lookup
↓
3. Fall back to Symfony getClientIp() → Perform GeoIP database lookup → Return country
Dual Detection Strategy
-
Primary: Cloudflare Headers (instant results)
CF-IPCountry: ISO 3166-1 alpha-2 country codeCF-Connecting-IP: Real client IP address
-
Fallback: GeoIP Database Lookup
- MaxMind GeoLite2/GeoIP2 Country database
- Handles cases where CF headers are missing or invalid
🚀 Installation
Via Composer
composer require gryfoss/http-cf-geolocation-service
Requirements
- PHP: 8.1 or higher
- Extensions: mbstring, filter
- Dependencies:
symfony/http-foundation^7.3geoip2/geoip2^3.2
📖 Usage
Basic Usage
<?php use GryfOSS\Geolocation\CFGeolocationService; use Symfony\Component\HttpFoundation\Request; // Initialize with GeoIP database path $service = new CFGeolocationService('/path/to/GeoLite2-Country.mmdb'); // Get current request $request = Request::createFromGlobals(); // Detect client IP address $clientIp = $service->getIp($request); echo "Client IP: " . $clientIp; // e.g., "203.0.113.1" // Detect country code $countryCode = $service->getCountryCode($request); echo "Country: " . $countryCode; // e.g., "US"
With Cloudflare Headers
When your application is behind Cloudflare, the service automatically uses CF headers:
// Cloudflare provides these headers: // CF-Connecting-IP: 203.0.113.1 // CF-IPCountry: US $countryCode = $service->getCountryCode($request); // Returns "US" instantly (no database lookup needed) $clientIp = $service->getIp($request); // Returns "203.0.113.1" (real client IP, not Cloudflare's)
Without Cloudflare Headers
The service gracefully falls back to GeoIP database lookup:
// No CF headers available $countryCode = $service->getCountryCode($request); // Performs GeoIP database lookup on client IP // Returns country code based on IP geolocation
Debug Mode for Local Development
When developing on localhost or behind corporate VPNs, Cloudflare headers might be unavailable. Enable debug mode to short-circuit lookups and return deterministic values without changing your stack:
$service->setDebugMode(true, '203.0.113.77', 'PL'); // Use fake IP + ISO code $clientIp = $service->getIp($request); // "203.0.113.77" $countryCode = $service->getCountryCode($request); // "PL" $service->setDebugMode(false); // Revert to normal detection
Use isDebugModeEnabled(), getDebugModeIp(), and getDebugModeCountryCode() to inspect the current state. Debug mode strictly validates both the IP address and ISO 3166-1 alpha-2 country code to avoid accidental misuse.
Error Handling
use GryfOSS\Geolocation\CFGeolocationService; try { $service = new CFGeolocationService('/invalid/path/database.mmdb'); } catch (\InvalidArgumentException $e) { echo "Database not found: " . $e->getMessage(); } try { $countryCode = $service->getCountryCode($request); } catch (\Exception $e) { echo "Geolocation failed: " . $e->getMessage(); }
Complete Examples
See examples.php for comprehensive usage examples including:
- Basic geolocation detection
- Cloudflare header simulation
- GeoIP database fallback scenarios
- Error handling demonstrations
- Testing with various IP addresses
# Run examples (requires database download first)
./pull-free-db.sh
php examples.php
🧪 Testing
Download GeoIP Database
⚠️ Important: Due to MaxMind's licensing restrictions, the GeoIP database cannot be bundled with this package. You must download it separately.
# Download free GeoLite2 database ./pull-free-db.sh # Or manually download from: # https://dev.maxmind.com/geoip/geoip2/geolite2/
Run Tests
# Install development dependencies composer install # Download test database ./pull-free-db.sh # Run complete test suite ./vendor/bin/phpunit # Run Behat functional specs (debug mode scenarios) ./vendor/bin/behat # Run tests with coverage XDEBUG_MODE=coverage ./vendor/bin/phpunit --coverage-text # Run tests with readable output ./vendor/bin/phpunit --testdox # Run usage examples php examples.php
Test Coverage
The project maintains 100% code coverage:
- ✅ Lines: 100%
- ✅ Methods: 100%
- ✅ Classes: 100%
# Verify coverage locally XDEBUG_MODE=coverage ./vendor/bin/phpunit --coverage-html coverage-report # Open coverage-report/index.html in your browser
Testing Strategy
- Unit Tests: 32 unit tests covering all methods and edge cases
- Integration Tests: 6 integration tests with real GeoIP database
- Total: 38 tests with 47 assertions
- Data Providers: Multiple test scenarios for various input combinations
- Exception Testing: Error handling and edge case validation
- Real Database: Tests use actual GeoLite2-Country.mmdb for authenticity
🗃️ GeoIP Database Setup
Database Licensing Notice
⚠️ Important Licensing Information
This package does not include the MaxMind GeoIP database due to licensing restrictions:
- GeoLite2 databases are available for free but require separate download
- Commercial GeoIP2 databases require a MaxMind license
- Distribution restrictions prevent bundling databases with open-source packages
Download Options
Option 1: Free GeoLite2 Database
# Use the included script ./pull-free-db.sh # Manual download wget https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-Country.mmdb
Option 2: Official MaxMind Account
- Create account at MaxMind
- Generate license key
- Download GeoLite2 or purchase GeoIP2 databases
- Follow MaxMind's terms of service
Option 3: Automated Updates
# Set up cron job for monthly updates 0 0 1 * * /path/to/your/project/pull-free-db.sh
Database Paths
// Common database locations $service = new CFGeolocationService('/usr/local/share/GeoIP/GeoLite2-Country.mmdb'); $service = new CFGeolocationService('/var/lib/GeoIP/GeoLite2-Country.mmdb'); $service = new CFGeolocationService('./data/GeoLite2-Country.mmdb');
🔧 Configuration
Environment Variables
# Set database path via environment export GEOIP_DATABASE_PATH="/path/to/GeoLite2-Country.mmdb"
// Use in your application $databasePath = $_ENV['GEOIP_DATABASE_PATH'] ?? '/default/path/GeoLite2-Country.mmdb'; $service = new CFGeolocationService($databasePath);
Framework Integration
Symfony
# config/services.yaml services: GryfOSS\Geolocation\CFGeolocationService: arguments: $databasePath: '%env(GEOIP_DATABASE_PATH)%'
Laravel
// config/app.php or service provider $this->app->singleton(CFGeolocationService::class, function ($app) { return new CFGeolocationService(env('GEOIP_DATABASE_PATH')); });
🏆 Quality Assurance
GitHub Actions CI/CD
- Multi-PHP Testing: 8.2, 8.3, 8.4
- Automated Database Download: Fresh GeoLite2 database for each test run
- 100% Coverage Enforcement: Builds fail if coverage drops below 100%
- Cross-Platform: Ubuntu latest with comprehensive test matrix
Code Quality Standards
- PSR-4 Autoloading: Namespace compliance
- PHPDoc Documentation: Comprehensive method and class documentation
- Type Declarations: Strict typing for all parameters and returns
- Error Handling: Graceful exception handling for all failure modes
- Input Validation: Thorough validation of all external inputs
🤝 Contributing
We welcome contributions from the community! Here's how you can help:
Reporting Issues
- Bug Reports: Use the GitHub Issues to report bugs
- Feature Requests: Propose new features or improvements
- Security Issues: Report security vulnerabilities privately
Pull Requests
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes with tests
- Ensure 100% test coverage:
XDEBUG_MODE=coverage ./vendor/bin/phpunit --coverage-text - Follow coding standards: PSR-12 compliance
- Submit a pull request with detailed description
Development Guidelines
- Write tests first: TDD approach preferred
- Maintain 100% coverage: All new code must be fully tested
- Follow existing patterns: Consistent with current codebase
- Document thoroughly: PHPDoc for all public methods
- Validate inputs: Handle edge cases gracefully
Code of Conduct
Please follow our code of conduct in all interactions:
- Be respectful and inclusive
- Focus on constructive feedback
- Help others learn and grow
- Maintain professionalism
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
👥 Authors
- IDCT Bartosz Pachołek - GitHub - Initial work
🙏 Acknowledgments
- MaxMind for providing GeoIP2 and GeoLite2 databases
- Cloudflare for their excellent geolocation headers
- Symfony for the robust HTTP foundation component
- P3TERX for maintaining the GeoLite2 mirror repository
- PHP Community for continuous improvements and feedback
📚 Additional Resources
Made with ❤️ by the GryfOSS team
统计信息
- 总下载量: 27
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 0
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-11-12