When building WordPress plugins or any server-dependent PHP application, detecting the underlying web server is crucial for proper configuration. The challenge lies in the numerous possible server combinations and proxy setups that can obscure the actual server software.
The most straightforward approach examines the $_SERVER['SERVER_SOFTWARE']
variable:
function detectWebServer() {
if (isset($_SERVER['SERVER_SOFTWARE'])) {
$software = strtolower($_SERVER['SERVER_SOFTWARE']);
if (strpos($software, 'apache') !== false) {
return 'Apache';
} elseif (strpos($software, 'nginx') !== false) {
return 'Nginx';
} elseif (strpos($software, 'microsoft-iis') !== false) {
return 'IIS';
} elseif (strpos($software, 'lighttpd') !== false) {
return 'Lighttpd';
}
}
return 'Unknown';
}
For more complex environments with proxies or load balancers, we need additional checks:
function advancedServerDetection() {
// Check for common proxy headers
$headers = array(
'SERVER_SOFTWARE',
'X-Powered-By',
'SERVER_SIGNATURE',
'X-Server'
);
$serverData = array();
foreach ($headers as $header) {
if (isset($_SERVER[$header])) {
$serverData[] = $_SERVER[$header];
}
}
// Check specific PHP SAPI
if (php_sapi_name() === 'fpm-fcgi') {
$serverData[] = 'PHP-FPM';
}
// Analyze collected data
$combined = strtolower(implode('|', $serverData));
if (strpos($combined, 'apache') !== false) {
return 'Apache';
} elseif (strpos($combined, 'nginx') !== false) {
return 'Nginx';
} elseif (strpos($combined, 'microsoft-iis') !== false) {
return 'IIS';
}
// Fallback to SAPI detection
if (strpos(php_sapi_name(), 'apache') !== false) {
return 'Apache (module)';
}
return 'Unknown';
}
For reverse proxy setups where traffic passes through Nginx to Apache:
function detectWithProxy() {
// Check X-Forwarded-Server header first
if (isset($_SERVER['HTTP_X_FORWARDED_SERVER'])) {
$forwarded = strtolower($_SERVER['HTTP_X_FORWARDED_SERVER']);
if (strpos($forwarded, 'nginx') !== false) {
return 'Nginx (reverse proxy)';
}
}
// Fall back to regular detection
return advancedServerDetection();
}
For WordPress plugins, we can enhance detection with WP-specific functions:
function wpDetectServer() {
// Check for WP-CLI
if (defined('WP_CLI') && WP_CLI) {
return 'WP-CLI';
}
// Check for IIS with URL Rewrite
if (isset($_SERVER['IIS_WasUrlRewritten']) && $_SERVER['IIS_WasUrlRewritten']) {
return 'IIS with URL Rewrite';
}
// Standard detection
$server = detectWithProxy();
// Additional WP-specific checks
if ($server === 'Unknown') {
if (function_exists('is_nginx') && is_nginx()) {
return 'Nginx (WP detected)';
}
}
return $server;
}
When developing server-specific optimizations or configurations in PHP (like WordPress plugins), accurately detecting the underlying web server is crucial. The $_SERVER['SERVER_SOFTWARE']
superglobal is the primary source, but we need robust handling for various environments.
function detectWebServer() {
$server_software = $_SERVER['SERVER_SOFTWARE'] ?? '';
// Standard detection
if (stripos($server_software, 'Apache') !== false) {
return 'Apache';
} elseif (stripos($server_software, 'nginx') !== false) {
return 'Nginx';
} elseif (stripos($server_software, 'Microsoft-IIS') !== false) {
return 'IIS';
} elseif (stripos($server_software, 'LiteSpeed') !== false) {
return 'LiteSpeed';
}
// Additional checks when behind proxies
$via = $_SERVER['HTTP_VIA'] ?? '';
$forwarded = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? '';
if (!empty($via) || !empty($forwarded)) {
// Check for common proxy headers
if (isset($_SERVER['HTTP_X_SERVER_SOFTWARE'])) {
$proxy_software = $_SERVER['HTTP_X_SERVER_SOFTWARE'];
if (stripos($proxy_software, 'nginx') !== false) {
return 'Nginx (behind proxy)';
}
}
}
// Fallback for PHP built-in server
if (php_sapi_name() === 'cli-server') {
return 'PHP Development Server';
}
return 'Unknown';
}
For complex setups like Apache+Nginx reverse proxy or PHP-FPM:
function advancedServerDetection() {
// Check for FastCGI
if (stripos(php_sapi_name(), 'fpm') !== false) {
return 'PHP-FPM';
}
// Check for CGI
if (strpos(php_sapi_name(), 'cgi') !== false) {
return 'CGI Handler';
}
// Check server headers when behind load balancers
$serverHeaders = [
'SERVER_SOFTWARE',
'X_Powered_By',
'X-Server',
'Server'
];
foreach ($serverHeaders as $header) {
if (isset($_SERVER[$header])) {
$value = strtolower($_SERVER[$header]);
if (strpos($value, 'nginx') !== false) return 'Nginx';
if (strpos($value, 'apache') !== false) return 'Apache';
}
}
return detectWebServer(); // Fallback to basic detection
}
Here's how to implement this in a WordPress plugin:
add_action('admin_init', 'check_server_environment');
function check_server_environment() {
$server = advancedServerDetection();
switch ($server) {
case 'Apache':
// Apply Apache-specific optimizations
add_filter('mod_rewrite_rules', 'custom_apache_rules');
break;
case 'Nginx':
// Apply Nginx-specific optimizations
add_action('admin_notices', 'nginx_config_notice');
break;
case 'PHP-FPM':
// Optimize for PHP-FPM
ini_set('pm.max_children', 50);
break;
default:
// Generic fallback
break;
}
}
Always verify your detection logic across multiple environments:
// Test cases
$testEnvironments = [
'Apache' => 'Apache/2.4.41 (Ubuntu)',
'Nginx' => 'nginx/1.18.0',
'IIS' => 'Microsoft-IIS/10.0',
'CloudFront' => 'Amazon CloudFront',
'LiteSpeed' => 'LiteSpeed',
'Unknown' => 'Caddy'
];
foreach ($testEnvironments as $expected => $input) {
$_SERVER['SERVER_SOFTWARE'] = $input;
$result = detectWebServer();
echo "Expected: $expected, Got: $result" . PHP_EOL;
}