Anne van Kesteren

PHP and 'application/xhtml+xml'

To answer the question from Christoph Wagner in Content Negotiation:

how to serve PHP docs as application/xhtml+xml at all, cause if I do, they aren't anymore parsed as PHP... ;)

I currently use a solution that doesn't really work correctly according to Jim Ley and he's right obviously. He has modified the Accept header of Internet Explorer to explicitely state that he doesn't want application/xhtml+xml. (Played with the q value basically.) The solution I currently use I will probably switch in the future:

 $charset = "utf-8";
 $mime    = (stristr($_SERVER["HTTP_ACCEPT"],"application/xhtml+xml")) ? "application/xhtml+xml" : "text/html";


And I must say it works perfectly. Simon Jessey has written an article to explain a more detailed PHP solution that also addresses the q value. The problem is that his article also changes the contents to HTML when application/xhtml+xml isn't supported, which makes me wonder if he actually needed to use XHTML. Anyway: Serving up XHTML with the correct MIME type.

(A slightly unrelated note: bloglines now supports xml:base. Great!)

(This is not the insightful post about how PHP works with aplication/xhtml+xml that it could have been by the way.)


  1. I don't use the short form to include the xml thing, like you can see here:

    if ( stristr($_SERVER["HTTP_ACCEPT"],"application/xhtml+xml")) {
      header("Content-type: application/xhtml+xml");
      print "<?xml version="1.0" encoding="iso-8859-1"?>\n";
    else {
      header("Content-type: text/html");

    Posted by Frenzie at

  2. What when my browser accepts XHTML, but prefers HTML?

    Posted by Kris at

  3. How would you tell?

    Posted by Frenzie at

  4. What when my browser accepts XHTML, but prefers HTML?
    In this case you shouldn't view pages, that are XHTML 1.1 I think..
    And thanks Anne, now I just have to think if I'll exclude IE Users and instead give them a message to upgrade

    And why am I not allowed to mark my off topic remarks as off topic?

    Posted by Christoph Wagner at

  5. How would you tell?

    Credits to Eric,
    Accept: text/html;q=0.9, application/xhtml+xml

    In this case you shouldn't view pages, that are XHTML 1.1 I think..

    In the case of XHTML1.1, content-negotiation about whether to serve HTML or XHTML does not make sense. This topic is about when it is relevant, hence XHTML1.0.

    Posted by Kris at

  6. Kris, if your first comment was addressed at me; note that I already mentioned the q value in the post and that it was addressed in the article of Simon.

    Cristoph Wagner, maybe I will add such a feature later, for now, I will decide which comments are off topic or troll.

    Posted by Anne at

  7. The problem is that his article also changes the contents to HTML when application/xhtml+xml isn't supported, which makes me wonder if he actually needed to use XHTML.

    You are quite correct, Anne. At the moment, I do not need to use XHTML; however, I wanted a solution that would allow me to easily take advantage of some of the language's extensibility at some future date. This is part of the future-proofing philosophy that the World Wide Web Consortium has been promoting since it introduced the XHTML standard.

    Posted by Simon Jessey at

  8. Simon, you are aware that w3schools is not from the W3C? ;-). Also, when you are going to extend XHTML, how will you remain backwards compatible?

    Posted by Anne at

  9. text/html;q=0.9, application/xhtml+xml

    The above is what you say, however, Opera outputs this:

    text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1

    Does this mean that application/xml is Opera's favourite mime-type? Or think about IE, it only says */*. Mozilla outputs this:


    But anyway, that would mean that the only browser which is currently completely compatible without quirks (I'm not sure about Safari/Konqueror though) with application/xhtml+xml mime-type wouldn't get it. That doesn't seem quite the idea to me. :/

    Posted by Frenzie at

  10. And why would Mozilla not get it?

    Posted by Anne at

  11. Because according to Kris, one would check for the occurance of text/html;q=0.9 in the accept string for the preferred mime-type. As such, Mozilla would get text/html, unless I misunderstood him.

    Posted by Frenzie at

  12. Ehm - The precence of a "q-value" in Accept doesn't make a MIME-type preferred by simply being there...
    If you omit the "q-value" for any MIME-type in Your Accept-header it should automatically be assumed to have a value of 1.0...
    Thus if you specify Your MIME-type preference as text/html;q=0.9, application/xhtml+xml it should be interpreted by the receiving webserver roughly as "I prefer application/xhtml+xml over text/html if you can manage it please"... (since 1.0 > 0.9)

    Consider the "Mozilla Accept" example from above (slightly dissected):
    text/xml,application/xml,application/xhtml+xml, (No q specified -> q=1.0 for these)
    (again q=1.0 for this one as well)

    As You can see, Mozilla doesn't specify if it prefers "application/xml" over "application/xhtml+xml" or "text/xml" - only that it is more interested in receiving any of those three (or image/png ;) over eg. "text/html" or "text/plain"...

    The real problem in the code in comment #1 is that when you just look at the prescence of a particular MIME-type in Accept without looking for a possible "q=0" you might end upp serving "application/xhtml+xml" to a user agent that just can't swollow it even if that UA is trying it's best to prevent that from happening by using application/xhtml+xml;q=0 in its Accept-header...

    Further "q-details" in

    Posted by jarvklo at

  13. "View Response Headers" on Anne's site with WebDev toolbar, shows: application/xhtml+xml as a result. But checking through W3C Validator, shows up as: text/html?

    However, checking with W3C Validator, shows: application/xhtml+xml. Any idea why?

    Posted by huphtur at

  14. huphtur, that's because of some excessive UA-sniffing:

    function set_mime_type() {
     $mime_type = (stristr(
      $_SERVER['HTTP_ACCEPT'], "application/xhtml+xml") 
      OR strstr($_SERVER['HTTP_USER_AGENT'], 'W3C_Validator')
      OR strstr($_SERVER['HTTP_USER_AGENT'], 'WDG_SiteValidator')
      OR strstr($_SERVER['HTTP_USER_AGENT'], 'Opera 7')
      OR stristr($_SERVER['HTTP_USER_AGENT'], 'Opera/7')) ? 'application/xhtml+xml' : 'text/html';
      $mime_type .= '; charset=iso-8859-1';
      return $mime_type;

    This code falls flat on the same the relative quality factor issue that jarvklo mentions.

    Posted by Ethan at

  15. Tommy Olsson's logic:

    if(preg_match('/application/xhtml+xml(;q=(d+.d+))?/i', $HTTP_SERVER_VARS['HTTP_ACCEPT'], $matches)) {
     $xhtmlQ = (isset($matches[2]) ? $matches[2] : 1);
     if(preg_match('/text/html(;q=(d+.d+))?/i', $HTTP_SERVER_VARS['HTTP_ACCEPT'], $matches)) {
      $htmlQ = (isset($matches[2]) ? $matches[2] : 1);
      $xhtml = ($xhtmlQ > $htmlQ);
     } else {
      $xhtml = true;

    Posted by CK at

  16. I tried this in ASP and IE now wants to download all my pages... Is this normal, or is IE (again) not compatible :s If I check my server's logs, most IE users have an http_accept variable like: '*/*'

    Posted by aspfreakout at

  17. Yes unfortunately that is the way MSIE sends Accept-headers...

    But if you want a simple solution you could easilly use Anne's approach as outlined in the post if you modify it to take care of the "q=0-problem"...
    In pseudocode it would go something like this:

    if (application/xhtml+xml is in Accept and it does not have a "q=0") {   set MIME-type to "application/xhtml+xml";   [ ... ] } else {   set MIME-type to "text/html";   [ ... ] } 

    This approach always works since you can choose to ignore all q-values != 0 without risk...

    The browser only informs you of what it can handle and sometimes of what it prefers - it doesn't order or require you to do anything with the information contained in q-values if you don't want to (although it is probably "good practice" to at least try to listen for q=0-requests ;)

    Posted by jarvklo at

  18. Simon, you are aware that w3schools is not from the W3C? ;-). Also, when you are going to extend XHTML, how will you remain backwards compatible?

    When I re-read my comment, I realized that I gave the impression that I thought that w3schools was some kind of advocacy wing of the W3C. I didn't intend that, sorry.

    IF I ever get around to extending XHTML, it will depend heavily on sniffing the Accept header - something that is being avidly discussed here. Browsers that cannot accept the extended content will be served an alternative, I suppose. I haven't really thought about it.

    Posted by Simon Jessey at

  19. Source:

    This is some code I use regularly. Works for me, including specifying preference of one over the other, or absolutely "dissing" either of them.

    Posted by Jan! at