Apache MultiViews Content Negotiation Failing Specifically for PHP Files: Diagnosis and Solutions


1 views

Recently while upgrading from PHP 5.3.6 to 5.4.0 on an Apache 2.2.22 server, I encountered a peculiar behavior where MultiViews content negotiation stopped working specifically for .php files, while continuing to work normally for other file types like .txt. Here's the complete technical deep dive:

# Error observed in Apache logs
Negotiation: discovered file(s) matching request: /home/server1/htdocs/admin/contents (None could be negotiated)

The virtual host was configured with MultiViews enabled:

<Directory "/home/server1/htdocs">
    Options Indexes Includes FollowSymLinks MultiViews
    Order allow,deny
    Allow from all
    AllowOverride All
</Directory>

Additionally, these rewrite rules were present in .htaccess:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^([^\\./]*)$ index.php?t=$1 [L]
</IfModule>

After extensive testing, I discovered the issue stems from an interaction between three factors:

  1. The PHP handler configuration changed in the upgrade
  2. MultiViews negotiation priority
  3. RewriteRule interference

Option 1: Explicit Type Map

Create a type map file named contents.var in the same directory:

URI: contents

URI: contents.php
Content-type: application/x-httpd-php
Content-negotiation: 1.0

Option 2: Force PHP Handler

Add this to your Apache config or .htaccess:

<FilesMatch "^contents$">
    ForceType application/x-httpd-php
    SetHandler application/x-httpd-php
</FilesMatch>

Option 3: RewriteRule Adjustment

Modify the existing rewrite rule to exclude negotiated paths:

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !\.php$
RewriteRule ^([^\\./]*)$ index.php?t=$1 [L]
  • Always test content negotiation during PHP upgrades
  • Consider using explicit rewrites instead of MultiViews for PHP files
  • Monitor Apache error logs for negotiation warnings

When upgrading from PHP 5.3.6 to 5.4.0, many administrators encounter a peculiar issue where Apache's content negotiation suddenly stops working specifically for PHP files. The server logs show:

Negotiation: discovered file(s) matching request: /home/server1/htdocs/admin/contents 
(None could be negotiated)

This behavior occurs when three key Apache modules interact:

LoadModule negotiation_module modules/mod_negotiation.so
LoadModule mime_module modules/mod_mime.so
LoadModule php5_module modules/libphp5.so

The issue manifests when all these conditions are met:

  1. MultiViews is enabled in Directory configuration
  2. The requested URI has no file extension
  3. Only .php files exist for the requested resource

First, verify your MIME type configuration:

# In httpd.conf or apache2.conf
AddType application/x-httpd-php .php
AddHandler php5-script .php

Then check the negotiation priority:

# Create a test file called type-map in your directory
URI: contents

URI: contents.php
Content-type: application/x-httpd-php
Content-language: en

Your existing rewrite rules might interfere with negotiation:

RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^\\./]*)$ index.php?t=$1 [L]

Try modifying to:

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !\.php$
RewriteRule ^([^\./]*)$ index.php?t=$1 [L]

The PHP 5.4 handler registration changed. Verify your configuration includes:

<FilesMatch \.php$>
    SetHandler application/x-httpd-php
</FilesMatch>

If negotiation still fails, consider these approaches:

# Option 1: Force negotiation for PHP files
<Directory "/home/server1/htdocs">
    Options +MultiViews
    MultiviewsMatch Any
</Directory>

# Option 2: Explicit type map
<Files "contents">
    ForceType application/x-httpd-php
    SetHandler application/x-httpd-php
</Files>

Enable detailed logging:

LogLevel debug
NegotiationLog /var/log/apache2/negotiation.log

This will reveal why the negotiation fails specifically for PHP files while working for others like .txt.