Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to select content type from HTTP Accept header in PHP

I'm trying to build a standard compliant website framework which serves XHTML 1.1 as application/xhtml+xml or HTML 4.01 as text/html depending on the browser support. Currently it just looks for "application/xhtml+xml" anywhere in the accept header, and uses that if it exists, but that's not flexible - text/html might have a higher score. Also, it will become more complex when other formats (WAP, SVG, XForms etc.) are added. So, does anyone know of a tried and tested piece of PHP code to select, from a string array given by the server, either the one best supported by the client or an ordered list based on the client score?

like image 673
l0b0 Avatar asked Jun 26 '09 14:06

l0b0


People also ask

What is Content-Type in PHP header?

The Content-Type header is used to indicate the media type of the resource. The media type is a string sent along with the file indicating the format of the file. For example, for image file its media type will be like image/png or image/jpg, etc. In response, it tells about the type of returned content, to the client.

How can I get HTTP header in PHP?

The header() function in PHP sends a raw HTTP header to a client or browser. Before HTML, XML, JSON, or other output is given to a browser or client, the server sends raw data as header information with the request (particularly HTTP Request).

What is Content-Type and accept headers?

The "Content-Type" header field indicates the media type of the associated representation. The Accept header always indicates what kind of response from the server a client can accept. Content-type is about the content of the current request or response, depending on which kind of HTTP message it is applied.

What is */* in Accept header?

14.1 Accept The asterisk "*" character is used to group media types into ranges, with "*/*" indicating all media types and "type/*" indicating all subtypes of that type. The media-range MAY include media type parameters that are applicable to that range.


2 Answers

Little snippet from my library:

function getBestSupportedMimeType($mimeTypes = null) {
    // Values will be stored in this array
    $AcceptTypes = Array ();

    // Accept header is case insensitive, and whitespace isn’t important
    $accept = strtolower(str_replace(' ', '', $_SERVER['HTTP_ACCEPT']));
    // divide it into parts in the place of a ","
    $accept = explode(',', $accept);
    foreach ($accept as $a) {
        // the default quality is 1.
        $q = 1;
        // check if there is a different quality
        if (strpos($a, ';q=')) {
            // divide "mime/type;q=X" into two parts: "mime/type" i "X"
            list($a, $q) = explode(';q=', $a);
        }
        // mime-type $a is accepted with the quality $q
        // WARNING: $q == 0 means, that mime-type isn’t supported!
        $AcceptTypes[$a] = $q;
    }
    arsort($AcceptTypes);

    // if no parameter was passed, just return parsed data
    if (!$mimeTypes) return $AcceptTypes;

    $mimeTypes = array_map('strtolower', (array)$mimeTypes);

    // let’s check our supported types:
    foreach ($AcceptTypes as $mime => $q) {
       if ($q && in_array($mime, $mimeTypes)) return $mime;
    }
    // no mime-type found
    return null;
}

example usage:

$mime = getBestSupportedMimeType(Array ('application/xhtml+xml', 'text/html'));
like image 146
Maciej Łebkowski Avatar answered Oct 12 '22 11:10

Maciej Łebkowski


You can leverage apache's mod_negotiation module. This way you can use the full range of negotiation capabilities the module offers, including your own preferences for the content type (e,g, "I really want to deliver application/xhtml+xml, unless the client very much prefers something else"). basic solution:

  • create a .htaccess file with
    AddHandler type-map .var
    as contents
  • create a file foo.var with
    URI: foo
    URI: foo.php/html Content-type: text/html; qs=0.7
    URI: foo.php/xhtml Content-type: application/xhtml+xml; qs=0.8
    as contents
  • create a file foo.php with
    <?php
    echo 'selected type: ', substr($_SERVER['PATH_INFO'], 1);
    as contents.
  • request http://localhost/whatever/foo.var

For this to work you need mod_negotiation enabled, the appropriate AllowOverride privileges for AddHandler and AcceptPathInfo not being disabled for $_SERVER['PATH_INFO'].
With my Firefox sending "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8" and the example .var map the result is "selected type: xhtml".
You can use other "tweaks" to get rid of PATH_INFO or the need to request foo.var, but the basic concept is: let mod_negotiation redirect the request to your php script in a way that the script can "read" the selected content-type.

So, does anyone know of a tried and tested piece of PHP code to select
It's not a pure php solution but I'd say mod_negotiation has been tried and tested ;-)
like image 21
VolkerK Avatar answered Oct 12 '22 13:10

VolkerK