Sponsor: The CSS Anthology
The CSS Anthology: 101 Essential Tips, Tricks & Hacks (external link)
Blog Entry
Content Negotiation
Published on the 1st of April 2005
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:
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:
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.
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.
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.
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.
Sponsor: Songbird Media Player
Desktop web player, a digital jukebox, and web browser mash-up. (external link)

