-
Notifications
You must be signed in to change notification settings - Fork 0
Client Detection
Rumen Damyanov edited this page Jul 31, 2025
·
1 revision
Comprehensive guide to detecting and using browser, device, operating system, and resolution information.
- Overview
- Browser Detection
- Operating System Detection
- Device Type Detection
- Screen Resolution
- User Agent Analysis
- Practical Applications
- Advanced Patterns
- Testing and Validation
The php-geolocation package provides comprehensive client detection capabilities beyond just country detection. This information helps you:
- Optimize User Experience: Serve appropriate layouts for different devices
- Feature Detection: Enable/disable features based on browser capabilities
- Analytics: Track visitor demographics and technology usage
- Performance: Optimize content delivery based on device capabilities
- Security: Identify potential security threats or unusual patterns
use Rumenx\Geolocation\Geolocation;
$geo = new Geolocation();
$clientInfo = $geo->getGeoInfo([
'browser', // Browser name and version
'os', // Operating system
'device', // Device type (desktop/mobile/tablet)
'resolution' // Screen resolution
]);
print_r($clientInfo);
/* Output:
Array (
[browser] => Array (
[browser] => Chrome
[version] => 91.0.4472.124
)
[os] => Windows 10
[device] => desktop
[resolution] => Array (
[width] => 1920
[height] => 1080
)
)
*/$geo = new Geolocation();
$browser = $geo->getBrowser();
if ($browser) {
echo "Browser: {$browser['browser']}\n";
echo "Version: {$browser['version']}\n";
// Browser-specific logic
switch ($browser['browser']) {
case 'Chrome':
$features = ['webp', 'modern-js', 'css-grid'];
break;
case 'Firefox':
$features = ['webp', 'modern-js', 'css-grid'];
break;
case 'Safari':
$features = ['webp', 'modern-js', 'css-grid'];
$safariVersion = floatval($browser['version']);
if ($safariVersion < 14) {
// Remove features not supported in older Safari
$features = array_diff($features, ['webp']);
}
break;
case 'Internet Explorer':
$features = ['legacy-support'];
break;
default:
$features = ['basic'];
}
echo "Supported features: " . implode(', ', $features) . "\n";
}function compareBrowserVersion($browser, $requiredBrowser, $requiredVersion) {
if (!$browser || $browser['browser'] !== $requiredBrowser) {
return false;
}
return version_compare($browser['version'], $requiredVersion, '>=');
}
$geo = new Geolocation();
$browser = $geo->getBrowser();
// Check for modern browser features
$supportsModernJS =
compareBrowserVersion($browser, 'Chrome', '60') ||
compareBrowserVersion($browser, 'Firefox', '55') ||
compareBrowserVersion($browser, 'Safari', '12') ||
compareBrowserVersion($browser, 'Edge', '79');
if ($supportsModernJS) {
echo '<script type="module" src="modern-app.js"></script>';
} else {
echo '<script src="legacy-app.js"></script>';
}class BrowserCapabilities
{
private $browser;
public function __construct($browser) {
$this->browser = $browser;
}
public function supportsWebP(): bool {
if (!$this->browser) return false;
$name = $this->browser['browser'];
$version = floatval($this->browser['version']);
switch ($name) {
case 'Chrome':
return $version >= 23;
case 'Firefox':
return $version >= 65;
case 'Safari':
return $version >= 14;
case 'Edge':
return $version >= 18;
default:
return false;
}
}
public function supportsAVIF(): bool {
if (!$this->browser) return false;
$name = $this->browser['browser'];
$version = floatval($this->browser['version']);
switch ($name) {
case 'Chrome':
return $version >= 85;
case 'Firefox':
return $version >= 93;
default:
return false;
}
}
public function supportsCSSGrid(): bool {
if (!$this->browser) return false;
$name = $this->browser['browser'];
$version = floatval($this->browser['version']);
switch ($name) {
case 'Chrome':
return $version >= 57;
case 'Firefox':
return $version >= 52;
case 'Safari':
return $version >= 10.1;
case 'Edge':
return $version >= 16;
default:
return false;
}
}
public function getImageFormat(): string {
if ($this->supportsAVIF()) {
return 'avif';
} elseif ($this->supportsWebP()) {
return 'webp';
} else {
return 'jpg';
}
}
}
// Usage
$geo = new Geolocation();
$browser = $geo->getBrowser();
$capabilities = new BrowserCapabilities($browser);
$imageFormat = $capabilities->getImageFormat();
echo "Best image format: {$imageFormat}\n";
if ($capabilities->supportsCSSGrid()) {
echo '<link rel="stylesheet" href="grid-layout.css">';
} else {
echo '<link rel="stylesheet" href="flexbox-layout.css">';
}$geo = new Geolocation();
$os = $geo->getOs();
if ($os) {
echo "Operating System: {$os}\n";
// OS-specific logic
if (stripos($os, 'Windows') !== false) {
$downloadLink = '/downloads/app-windows.exe';
$installInstructions = 'Double-click to install';
} elseif (stripos($os, 'Mac') !== false) {
$downloadLink = '/downloads/app-macos.dmg';
$installInstructions = 'Drag to Applications folder';
} elseif (stripos($os, 'Linux') !== false) {
$downloadLink = '/downloads/app-linux.tar.gz';
$installInstructions = 'Extract and run install.sh';
} elseif (stripos($os, 'Android') !== false) {
$downloadLink = 'https://play.google.com/store/apps/details?id=com.example.app';
$installInstructions = 'Install from Google Play Store';
} elseif (stripos($os, 'iOS') !== false) {
$downloadLink = 'https://apps.apple.com/app/example-app/id123456789';
$installInstructions = 'Install from App Store';
} else {
$downloadLink = '/downloads/';
$installInstructions = 'Choose your platform';
}
echo "Download: {$downloadLink}\n";
echo "Instructions: {$installInstructions}\n";
}function parseOSVersion($osString) {
$patterns = [
'/Windows NT (\d+\.\d+)/' => [
'10.0' => 'Windows 10/11',
'6.3' => 'Windows 8.1',
'6.2' => 'Windows 8',
'6.1' => 'Windows 7',
'6.0' => 'Windows Vista'
],
'/Mac OS X (\d+)[_.](\d+)/' => 'macOS',
'/Android (\d+\.\d+)/' => 'Android',
'/iPhone OS (\d+)[_.](\d+)/' => 'iOS',
'/Ubuntu\/(\d+\.\d+)/' => 'Ubuntu Linux'
];
foreach ($patterns as $pattern => $mapping) {
if (preg_match($pattern, $osString, $matches)) {
if (is_array($mapping)) {
return $mapping[$matches[1]] ?? "Windows {$matches[1]}";
} else {
return "{$mapping} {$matches[1]}";
}
}
}
return $osString;
}
$geo = new Geolocation();
$os = $geo->getOs();
$detailedOS = parseOSVersion($_SERVER['HTTP_USER_AGENT'] ?? '');
echo "Basic OS: {$os}\n";
echo "Detailed OS: {$detailedOS}\n";class OSFeatures
{
private $os;
public function __construct($os) {
$this->os = strtolower($os ?? '');
}
public function supportsPWA(): bool {
// Progressive Web App support
return strpos($this->os, 'android') !== false ||
strpos($this->os, 'windows 10') !== false ||
strpos($this->os, 'macos') !== false;
}
public function supportsNotifications(): bool {
return strpos($this->os, 'windows') !== false ||
strpos($this->os, 'macos') !== false ||
strpos($this->os, 'linux') !== false;
}
public function getKeyboardShortcuts(): array {
if (strpos($this->os, 'mac') !== false) {
return [
'copy' => 'Cmd+C',
'paste' => 'Cmd+V',
'save' => 'Cmd+S'
];
} else {
return [
'copy' => 'Ctrl+C',
'paste' => 'Ctrl+V',
'save' => 'Ctrl+S'
];
}
}
public function getFileManager(): string {
if (strpos($this->os, 'windows') !== false) {
return 'File Explorer';
} elseif (strpos($this->os, 'mac') !== false) {
return 'Finder';
} else {
return 'File Manager';
}
}
}
// Usage
$geo = new Geolocation();
$osFeatures = new OSFeatures($geo->getOs());
if ($osFeatures->supportsPWA()) {
echo '<link rel="manifest" href="/manifest.json">';
echo '<meta name="theme-color" content="#000000">';
}
$shortcuts = $osFeatures->getKeyboardShortcuts();
echo "Copy shortcut: {$shortcuts['copy']}\n";$geo = new Geolocation();
$device = $geo->getDeviceType();
switch ($device) {
case 'mobile':
$viewport = '<meta name="viewport" content="width=device-width, initial-scale=1.0">';
$css = 'mobile.css';
$jsFramework = 'mobile-framework.js';
$features = ['touch', 'compact-ui', 'swipe-gestures'];
break;
case 'tablet':
$viewport = '<meta name="viewport" content="width=device-width, initial-scale=1.0">';
$css = 'tablet.css';
$jsFramework = 'touch-framework.js';
$features = ['touch', 'medium-ui', 'orientation-change'];
break;
case 'desktop':
default:
$viewport = '';
$css = 'desktop.css';
$jsFramework = 'full-framework.js';
$features = ['mouse', 'keyboard', 'full-ui', 'hover-effects'];
break;
}
echo $viewport . "\n";
echo "<link rel=\"stylesheet\" href=\"{$css}\">\n";
echo "<script src=\"{$jsFramework}\"></script>\n";
echo "Available features: " . implode(', ', $features) . "\n";class ResponsiveHelper
{
private $device;
private $resolution;
public function __construct($device, $resolution) {
$this->device = $device;
$this->resolution = $resolution;
}
public function getLayoutColumns(): int {
switch ($this->device) {
case 'mobile':
return 1;
case 'tablet':
return 2;
case 'desktop':
if ($this->resolution['width'] >= 1920) {
return 4;
} elseif ($this->resolution['width'] >= 1200) {
return 3;
} else {
return 2;
}
default:
return 2;
}
}
public function getImageSizes(): array {
switch ($this->device) {
case 'mobile':
return [
'thumbnail' => '150x150',
'medium' => '300x200',
'large' => '600x400'
];
case 'tablet':
return [
'thumbnail' => '200x200',
'medium' => '400x300',
'large' => '800x600'
];
case 'desktop':
return [
'thumbnail' => '250x250',
'medium' => '500x400',
'large' => '1200x800'
];
default:
return [
'thumbnail' => '150x150',
'medium' => '300x200',
'large' => '600x400'
];
}
}
public function shouldLazyLoad(): bool {
// Enable lazy loading for mobile to save bandwidth
return $this->device === 'mobile';
}
public function getNavigationType(): string {
switch ($this->device) {
case 'mobile':
return 'hamburger';
case 'tablet':
return 'tabs';
case 'desktop':
return 'horizontal';
default:
return 'horizontal';
}
}
}
// Usage
$geo = new Geolocation();
$device = $geo->getDeviceType();
$resolution = $geo->getResolution();
$helper = new ResponsiveHelper($device, $resolution);
$columns = $helper->getLayoutColumns();
$imageSizes = $helper->getImageSizes();
$navigation = $helper->getNavigationType();
echo "Layout columns: {$columns}\n";
echo "Navigation type: {$navigation}\n";
echo "Large image size: {$imageSizes['large']}\n";
if ($helper->shouldLazyLoad()) {
echo '<script src="lazy-loading.js"></script>';
}$geo = new Geolocation();
$resolution = $geo->getResolution();
if ($resolution['width'] && $resolution['height']) {
$width = $resolution['width'];
$height = $resolution['height'];
// Determine resolution category
if ($width >= 3840) {
$category = '4K';
$imageQuality = 'ultra-high';
$maxImageWidth = 2400;
} elseif ($width >= 2560) {
$category = '2K/QHD';
$imageQuality = 'high';
$maxImageWidth = 1800;
} elseif ($width >= 1920) {
$category = 'Full HD';
$imageQuality = 'high';
$maxImageWidth = 1200;
} elseif ($width >= 1366) {
$category = 'HD';
$imageQuality = 'medium';
$maxImageWidth = 800;
} else {
$category = 'Standard';
$imageQuality = 'low';
$maxImageWidth = 600;
}
echo "Resolution: {$width}x{$height} ({$category})\n";
echo "Image quality: {$imageQuality}\n";
echo "Max image width: {$maxImageWidth}px\n";
// Responsive image srcset
$imageSrcset = generateResponsiveImages('hero-image', $maxImageWidth);
echo "Responsive images: {$imageSrcset}\n";
}
function generateResponsiveImages($imageName, $maxWidth) {
$sizes = [
intval($maxWidth * 0.5),
intval($maxWidth * 0.75),
$maxWidth
];
$srcset = [];
foreach ($sizes as $size) {
$srcset[] = "/images/{$imageName}-{$size}w.jpg {$size}w";
}
return implode(', ', $srcset);
}function detectHighDPI($resolution, $device) {
$width = $resolution['width'];
$height = $resolution['height'];
// Common high DPI scenarios
$highDPIPatterns = [
// Retina displays
['min_width' => 2880, 'device' => 'desktop'], // 5K iMac
['min_width' => 2560, 'device' => 'desktop'], // 4K/Retina
['min_width' => 1440, 'device' => 'mobile'], // iPhone Plus/Pro
['min_width' => 1125, 'device' => 'mobile'], // iPhone standard
['min_width' => 2048, 'device' => 'tablet'], // iPad Retina
];
foreach ($highDPIPatterns as $pattern) {
if ($width >= $pattern['min_width'] &&
$device === $pattern['device']) {
return true;
}
}
// Density-based detection (approximate)
if ($device === 'mobile' && $width > 720) {
return true;
}
if ($device === 'desktop' && $width >= 2560) {
return true;
}
return false;
}
$geo = new Geolocation();
$resolution = $geo->getResolution();
$device = $geo->getDeviceType();
$isHighDPI = detectHighDPI($resolution, $device);
if ($isHighDPI) {
echo '<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">';
echo '<!-- High DPI optimizations -->';
echo '<link rel="stylesheet" href="retina.css">';
// Serve 2x images
$imageMultiplier = 2;
} else {
$imageMultiplier = 1;
}
echo "Image multiplier: {$imageMultiplier}x\n";class UserAgentAnalyzer
{
private $userAgent;
public function __construct($userAgent) {
$this->userAgent = $userAgent;
}
public function isMobile(): bool {
$mobilePatterns = [
'/Mobile/', '/Android/', '/iPhone/', '/iPad/',
'/Windows Phone/', '/BlackBerry/', '/Opera Mini/'
];
foreach ($mobilePatterns as $pattern) {
if (preg_match($pattern, $this->userAgent)) {
return true;
}
}
return false;
}
public function isBot(): bool {
$botPatterns = [
'/Googlebot/', '/Bingbot/', '/Slurp/', '/DuckDuckBot/',
'/Baiduspider/', '/YandexBot/', '/facebookexternalhit/',
'/Twitterbot/', '/LinkedInBot/', '/WhatsApp/', '/Telegram/'
];
foreach ($botPatterns as $pattern) {
if (preg_match($pattern, $this->userAgent)) {
return true;
}
}
return false;
}
public function getBotType(): ?string {
$bots = [
'Googlebot' => 'Search Engine',
'Bingbot' => 'Search Engine',
'facebookexternalhit' => 'Social Media',
'Twitterbot' => 'Social Media',
'LinkedInBot' => 'Social Media',
'WhatsApp' => 'Messaging',
'Telegram' => 'Messaging'
];
foreach ($bots as $bot => $type) {
if (strpos($this->userAgent, $bot) !== false) {
return $type;
}
}
return null;
}
public function isHeadless(): bool {
$headlessPatterns = [
'/HeadlessChrome/', '/PhantomJS/', '/Selenium/',
'/puppeteer/', '/playwright/'
];
foreach ($headlessPatterns as $pattern) {
if (preg_match($pattern, $this->userAgent)) {
return true;
}
}
return false;
}
public function getEngineVersion(): ?array {
$engines = [
'WebKit' => '/WebKit\/(\d+\.\d+)/',
'Gecko' => '/Gecko\/(\d+)/',
'Trident' => '/Trident\/(\d+\.\d+)/',
'Blink' => '/Chrome\/(\d+)/' // Blink is used in Chrome
];
foreach ($engines as $engine => $pattern) {
if (preg_match($pattern, $this->userAgent, $matches)) {
return [
'engine' => $engine,
'version' => $matches[1]
];
}
}
return null;
}
}
// Usage
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? '';
$analyzer = new UserAgentAnalyzer($userAgent);
if ($analyzer->isBot()) {
$botType = $analyzer->getBotType();
echo "Bot detected: {$botType}\n";
// Handle bots differently
if ($botType === 'Search Engine') {
// Serve SEO-optimized content
include 'seo-optimized.php';
} elseif ($botType === 'Social Media') {
// Serve social media preview content
include 'social-preview.php';
}
} elseif ($analyzer->isHeadless()) {
echo "Headless browser detected\n";
// Handle automation/testing
} else {
echo "Regular user detected\n";
$engine = $analyzer->getEngineVersion();
if ($engine) {
echo "Browser engine: {$engine['engine']} v{$engine['version']}\n";
}
}class ContentOptimizer
{
private $geo;
public function __construct(Geolocation $geo) {
$this->geo = $geo;
}
public function optimizeForClient(): array {
$device = $this->geo->getDeviceType();
$browser = $this->geo->getBrowser();
$resolution = $this->geo->getResolution();
$optimizations = [
'css' => $this->getCSSOptimizations($device, $browser),
'js' => $this->getJSOptimizations($browser),
'images' => $this->getImageOptimizations($device, $resolution),
'layout' => $this->getLayoutOptimizations($device, $resolution)
];
return $optimizations;
}
private function getCSSOptimizations($device, $browser): array {
$css = ['base.css'];
// Device-specific CSS
switch ($device) {
case 'mobile':
$css[] = 'mobile.css';
break;
case 'tablet':
$css[] = 'tablet.css';
break;
case 'desktop':
$css[] = 'desktop.css';
break;
}
// Browser-specific CSS
if ($browser && $browser['browser'] === 'Safari') {
$css[] = 'safari-fixes.css';
} elseif ($browser && $browser['browser'] === 'Internet Explorer') {
$css[] = 'ie-compatibility.css';
}
return $css;
}
private function getJSOptimizations($browser): array {
$js = ['core.js'];
if ($browser) {
$browserName = $browser['browser'];
$version = floatval($browser['version']);
// Modern browsers get modern JS
if (($browserName === 'Chrome' && $version >= 60) ||
($browserName === 'Firefox' && $version >= 55) ||
($browserName === 'Safari' && $version >= 12)) {
$js[] = 'modern.js';
} else {
$js[] = 'legacy.js';
$js[] = 'polyfills.js';
}
}
return $js;
}
private function getImageOptimizations($device, $resolution): array {
$maxWidth = 800; // Default
if ($device === 'desktop' && $resolution['width'] >= 1920) {
$maxWidth = 1200;
} elseif ($device === 'tablet') {
$maxWidth = 768;
} elseif ($device === 'mobile') {
$maxWidth = 480;
}
return [
'max_width' => $maxWidth,
'quality' => $device === 'mobile' ? 80 : 90,
'format' => 'webp', // Could be dynamic based on browser support
'lazy_load' => $device === 'mobile'
];
}
private function getLayoutOptimizations($device, $resolution): array {
return [
'columns' => $this->calculateColumns($device, $resolution),
'sidebar' => $device !== 'mobile',
'compact_header' => $device === 'mobile',
'touch_targets' => in_array($device, ['mobile', 'tablet'])
];
}
private function calculateColumns($device, $resolution): int {
switch ($device) {
case 'mobile':
return 1;
case 'tablet':
return 2;
case 'desktop':
if ($resolution['width'] >= 1600) {
return 4;
} elseif ($resolution['width'] >= 1200) {
return 3;
} else {
return 2;
}
default:
return 2;
}
}
}
// Usage
$geo = new Geolocation();
$optimizer = new ContentOptimizer($geo);
$optimizations = $optimizer->optimizeForClient();
// Apply optimizations
foreach ($optimizations['css'] as $cssFile) {
echo "<link rel=\"stylesheet\" href=\"/css/{$cssFile}\">\n";
}
foreach ($optimizations['js'] as $jsFile) {
echo "<script src=\"/js/{$jsFile}\"></script>\n";
}
$imageOpts = $optimizations['images'];
echo "<!-- Image optimization: max-width={$imageOpts['max_width']}px, quality={$imageOpts['quality']}% -->\n";class FeatureDetector
{
private $browser;
private $device;
public function __construct($browser, $device) {
$this->browser = $browser;
$this->device = $device;
}
public function getRequiredPolyfills(): array {
$polyfills = [];
if (!$this->supportsES6()) {
$polyfills[] = 'babel-polyfill.js';
}
if (!$this->supportsFetch()) {
$polyfills[] = 'fetch-polyfill.js';
}
if (!$this->supportsPromises()) {
$polyfills[] = 'promise-polyfill.js';
}
if (!$this->supportsIntersectionObserver()) {
$polyfills[] = 'intersection-observer-polyfill.js';
}
if ($this->device === 'mobile' && !$this->supportsPassiveListeners()) {
$polyfills[] = 'passive-events-polyfill.js';
}
return $polyfills;
}
private function supportsES6(): bool {
if (!$this->browser) return false;
$name = $this->browser['browser'];
$version = floatval($this->browser['version']);
switch ($name) {
case 'Chrome':
return $version >= 51;
case 'Firefox':
return $version >= 54;
case 'Safari':
return $version >= 10;
case 'Edge':
return $version >= 14;
default:
return false;
}
}
private function supportsFetch(): bool {
if (!$this->browser) return false;
$name = $this->browser['browser'];
$version = floatval($this->browser['version']);
switch ($name) {
case 'Chrome':
return $version >= 42;
case 'Firefox':
return $version >= 39;
case 'Safari':
return $version >= 10.1;
case 'Edge':
return $version >= 14;
default:
return false;
}
}
private function supportsPromises(): bool {
if (!$this->browser) return false;
$name = $this->browser['browser'];
$version = floatval($this->browser['version']);
switch ($name) {
case 'Chrome':
return $version >= 32;
case 'Firefox':
return $version >= 29;
case 'Safari':
return $version >= 8;
case 'Edge':
return $version >= 12;
default:
return false;
}
}
private function supportsIntersectionObserver(): bool {
if (!$this->browser) return false;
$name = $this->browser['browser'];
$version = floatval($this->browser['version']);
switch ($name) {
case 'Chrome':
return $version >= 58;
case 'Firefox':
return $version >= 55;
case 'Safari':
return $version >= 12.1;
case 'Edge':
return $version >= 15;
default:
return false;
}
}
private function supportsPassiveListeners(): bool {
if (!$this->browser) return false;
$name = $this->browser['browser'];
$version = floatval($this->browser['version']);
switch ($name) {
case 'Chrome':
return $version >= 51;
case 'Firefox':
return $version >= 49;
case 'Safari':
return $version >= 10;
default:
return false;
}
}
}
// Usage
$geo = new Geolocation();
$detector = new FeatureDetector($geo->getBrowser(), $geo->getDeviceType());
$polyfills = $detector->getRequiredPolyfills();
foreach ($polyfills as $polyfill) {
echo "<script src=\"/polyfills/{$polyfill}\"></script>\n";
}class ClientFingerprint
{
private $geo;
public function __construct(Geolocation $geo) {
$this->geo = $geo;
}
public function generateFingerprint(): string {
$components = [
'country' => $this->geo->getCountryCode(),
'browser' => $this->geo->getBrowser(),
'os' => $this->geo->getOs(),
'device' => $this->geo->getDeviceType(),
'resolution' => $this->geo->getResolution(),
'language' => $this->geo->getPreferredLanguage(),
'ip_hash' => $this->hashIp($this->geo->getIp())
];
// Create a hash of all components
$fingerprint = hash('sha256', serialize($components));
return substr($fingerprint, 0, 16); // Short fingerprint
}
private function hashIp(?string $ip): string {
if (!$ip) return '';
// Hash IP for privacy (keep only network portion)
$parts = explode('.', $ip);
if (count($parts) === 4) {
// IPv4: Keep first 3 octets, hash the last
$networkPart = implode('.', array_slice($parts, 0, 3));
return $networkPart . '.' . hash('crc32', $parts[3]);
}
return hash('crc32', $ip);
}
public function isUniqueVisitor(string $fingerprint): bool {
// Check against stored fingerprints (implement your storage logic)
$storedFingerprints = $this->getStoredFingerprints();
return !in_array($fingerprint, $storedFingerprints);
}
private function getStoredFingerprints(): array {
// Implement your storage logic (database, cache, etc.)
// This is just a placeholder
return [];
}
}
// Usage
$geo = new Geolocation();
$fingerprinter = new ClientFingerprint($geo);
$fingerprint = $fingerprinter->generateFingerprint();
echo "Client fingerprint: {$fingerprint}\n";
if ($fingerprinter->isUniqueVisitor($fingerprint)) {
echo "New visitor detected\n";
// Track new visitor
} else {
echo "Returning visitor\n";
// Handle returning visitor
}function testClientDetection() {
echo "Testing Client Detection...\n\n";
$testCases = [
[
'name' => 'Desktop Chrome on Windows',
'user_agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'expected' => [
'browser' => 'Chrome',
'os' => 'Windows 10',
'device' => 'desktop'
]
],
[
'name' => 'iPhone Safari',
'user_agent' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1',
'expected' => [
'browser' => 'Safari',
'os' => 'iOS',
'device' => 'mobile'
]
],
[
'name' => 'Android Chrome',
'user_agent' => 'Mozilla/5.0 (Linux; Android 11; SM-G975F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36',
'expected' => [
'browser' => 'Chrome',
'os' => 'Android',
'device' => 'mobile'
]
]
];
foreach ($testCases as $case) {
echo "Testing: {$case['name']}\n";
// Simulate the user agent
$_SERVER['HTTP_USER_AGENT'] = $case['user_agent'];
$geo = new Geolocation($_SERVER);
$browser = $geo->getBrowser();
$os = $geo->getOs();
$device = $geo->getDeviceType();
// Check results
$browserMatch = $browser && strpos($browser['browser'], $case['expected']['browser']) !== false;
$osMatch = strpos($os ?? '', $case['expected']['os']) !== false;
$deviceMatch = $device === $case['expected']['device'];
echo " Browser: " . ($browserMatch ? '✅' : '❌') . " {$browser['browser'] ?? 'Unknown'}\n";
echo " OS: " . ($osMatch ? '✅' : '❌') . " {$os ?? 'Unknown'}\n";
echo " Device: " . ($deviceMatch ? '✅' : '❌') . " {$device ?? 'Unknown'}\n";
echo "\n";
}
}
testClientDetection();function benchmarkClientDetection() {
echo "Benchmarking Client Detection Performance...\n\n";
$iterations = 1000;
$userAgents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Mozilla/5.0 (iPhone; CPU iPhone OS 14_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
];
$methods = [
'getBrowser' => 'Browser Detection',
'getOs' => 'OS Detection',
'getDeviceType' => 'Device Detection',
'getGeoInfo' => 'Complete Info'
];
foreach ($methods as $method => $description) {
$totalTime = 0;
for ($i = 0; $i < $iterations; $i++) {
$_SERVER['HTTP_USER_AGENT'] = $userAgents[$i % count($userAgents)];
$geo = new Geolocation($_SERVER);
$start = microtime(true);
$geo->$method();
$end = microtime(true);
$totalTime += ($end - $start);
}
$avgTime = ($totalTime / $iterations) * 1000; // Convert to milliseconds
echo "{$description}: {$avgTime:.3f}ms average\n";
}
}
benchmarkClientDetection();- ⚙️ Configuration - Advanced configuration options and customization
- 🔧 Troubleshooting - Common issues and solutions
- 🌍 Multi-language Websites - Complete internationalization examples
- 📊 Analytics Integration - Track geolocation and client data
Previous: API Reference | Next: Configuration