Breadcrumbs

Content Negotiation

In this entry I will discuss how to use content negotiation to your advantage and offer the correct mime-type for your code to the browsers which can handle it.

Last year, I only used to check the HTTP_ACCEPT header of a browser for the presence of application/xhtml+xml, which can be done easily by using:

Code: PHP

<?php
if (stristr($_SERVER['HTTP_ACCEPT'], 'application/xhtml+xml'))
{
    
}
?>

However, conversations with others showed me that this is not the right way to do this, because if a browser adds a q value to the HTTP_ACCEPT header (like application/xml;q=0.9), it's telling you that it accepts it, but doesn't prefer it above mime-types with a higher q value (no q-value means that it has a value of 1). Therefore we need to build-in another test before we serve the document as application/xhtml+xml:

Code: PHP

<?php
if (stristr($_SERVER['HTTP_ACCEPT'], 'application/xhtml+xml'))
{
    if (
preg_match('/application/xhtml+xml;q=0(.[1-9]+)/i'$_SERVER['HTTP_ACCEPT'], $matches))
    {
        
$xhtml_q $matches[1];
        
        if (
preg_match('/text/html;q=0(.[1-9]+)/i'$_SERVER['HTTP_ACCEPT'], $matches))
        {
            
$html_q $matches[1];
            
            if (
$xhtml_q >= $html_q)
            {
                
$mime 'application/xhtml+xml';
            }
        }
    }
    else
    {
        
$mime 'application/xhtml+xml';
    }
}
?>

This code checks which one of the mime-types you can offer is preferred by the browser. The default value of $mime was already set to text/html, because that is what any browser will be able to handle.

Next, you might be aware that the W3C validator is perfectly capable of handling application/xhtml+xml, but doesn't say so in its accept header. As such, we'll add a few extra lines.

Code: PHP

<?php
if (stristr($_SERVER['HTTP_USER_AGENT'],'WDG_Validator') || 
    
stristr($_SERVER['HTTP_USER_AGENT'],'W3C_Validator') || 
    
stristr($_SERVER['HTTP_USER_AGENT'],'W3C_CSS_Validator'
)

    
$mime 'application/xhtml+xml'
}
?>

Now the W3C Validator will receive application/xhtml+xml as we want it to.

We still need to modify the actual header information and, as a finishing touch, we want to state that the document is XML when it gets an XML mime-type.

Code: PHP

<?php
header
('Content-type: '.$mime);

if (
$mime == 'application/xhtml+xml')
{
    print 
'<?xml version="1.0" encoding="UTF-8"?>';
}
?>

The complete code will thus be as follows.

Code: PHP

<?php
$mime 
'text/html';

if (
stristr($_SERVER['HTTP_ACCEPT'],'application/xhtml+xml'))
{
    if(
preg_match('/application/xhtml+xml;q=0(.[1-9]+)/i',$_SERVER['HTTP_ACCEPT'],$matches))
    {
        
$xhtml_q $matches[1];
        
        if(
preg_match('/text/html;q=0(.[1-9]+)/i',$_SERVER['HTTP_ACCEPT'],$matches))
        {
            
$html_q $matches[1];
            
            if(
$xhtml_q >= $html_q)
            {
                
$mime 'application/xhtml+xml';
            }
        }
    }
    else
    {
        
$mime 'application/xhtml+xml';
    }
}

if (
stristr($_SERVER['HTTP_USER_AGENT'],'WDG_Validator') || stristr($_SERVER['HTTP_USER_AGENT'],'W3C_Validator') || stristr($_SERVER['HTTP_USER_AGENT'],'W3C_CSS_Validator'))
{
    
$mime 'application/xhtml+xml';
}

header('Content-type: '.$mime);

if (
$mime == 'application/xhtml+xml')
{
    echo 
'<?xml version="1.0" encoding="UTF-8"?>'."n";
}
?>

Before you add this to your site, you should ensure that it is well-formed, or display will break in conforming browsers. Enjoy.