How to Display Detailed PHP Errors in IIS Instead of Generic HTTP 500 Server Errors


4 views

When migrating from Apache to IIS for PHP hosting, the most frustrating difference is IIS's default behavior of swallowing PHP error details. While Apache typically shows syntax errors, undefined variables, and other debug information right in the browser, IIS often replaces these with generic HTTP 500 errors.

For PHP errors to surface in IIS, we need to configure three distinct layers:

// 1. PHP configuration (php.ini or runtime)
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);

// 2. IIS FastCGI settings
// Navigate to: IIS Manager → Server → FastCGI Settings → PHP → Edit
// Set "InstanceMaxRequests" to 10000
// Add environment variables:
//   PHP_FCGI_MAX_REQUESTS = 10000
//   PHPRC = C:\path\to\your\php.ini

// 3. IIS Error Pages (web.config)
<configuration>
  <system.webServer>
    <httpErrors errorMode="Detailed" />
    <asp scriptErrorSentToBrowser="true"/>
  </system.webServer>
</configuration>

The most confusing aspect is when some sites show errors while others don't. This typically stems from:

  • Different PHP handler mappings (check via IIS Manager → Site → Handler Mappings)
  • Conflicting web.config files in parent directories
  • Custom error pages overriding the defaults

When all else fails, IIS's Failed Request Tracing provides the most detailed logs:

# PowerShell command to enable tracing
Enable-WebRequestTracing -Name "PHP Debug" -Path "*.php" -StatusCodes 500

The trace files (typically in %SystemDrive%\inetpub\logs\FailedReqLogFiles) will show the exact point where PHP fails, including:

  • FastCGI communication details
  • Environment variables
  • Request/response headers

IIS often hides errors related to file permissions. Ensure:

  1. The IIS_IUSRS group has read/execute rights to PHP files
  2. Temporary directories (for sessions/uploads) are writable
  3. Custom error pages aren't intercepting the output

For AJAX calls returning 500 errors, modify the response header:

header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json');

http_response_code(500);
echo json_encode([
    'error' => [
        'message' => error_get_last()['message'],
        'type' => error_get_last()['type'],
        'file' => error_get_last()['file'],
        'line' => error_get_last()['line']
    ]
]);
die();

When migrating from Apache to IIS, developers often hit a wall when PHP errors get masked by generic HTTP 500 responses. Unlike Apache's verbose error reporting, IIS requires specific configuration to expose PHP's diagnostic messages.

First, ensure these PHP settings are in either php.ini or your script:

ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);

Navigate these key IIS configuration points:

1. web.config Settings

Add this to your site's web.config file:


  
    
    
  
  
    
    
  

2. FastCGI Verbosity

In IIS Manager:

  1. Open FastCGI Settings
  2. Edit PHP application
  3. Add environment variables:
    Name: PHP_FCGI_MAX_REQUESTS
    Value: 0
    
    Name: PHP_FCGI_STDERR
    Value: 1

For permission-related 500 errors:

icacls "C:\path\to\site" /grant "IIS_IUSRS:(OI)(CI)RX"

When dealing with custom error pages interfering:

Here's how we forced error display in a Laravel application:

// In public/index.php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

// In .env
APP_DEBUG=true

// In config/app.php
'debug' => env('APP_DEBUG', true),

When you can't see errors directly:

// Custom error logging
error_log(print_r(error_get_last(), true));

// Windows Event Viewer
// Filter for PHP-7.x entries