Skip to content

Instantly share code, notes, and snippets.

@kafene
Created July 18, 2014 06:18
Show Gist options
  • Save kafene/75e5754f0349412f61ca to your computer and use it in GitHub Desktop.
Save kafene/75e5754f0349412f61ca to your computer and use it in GitHub Desktop.
Parse accept headers per RFC-2616
<?php
# ref: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
function parse_accept_header($header, $field = "") {
# save original value
$orig_header = $header;
$header = preg_replace('/[\r\n\t]/', '', $header);
$field = strtolower(trim($field));
# Remove, e.g. "Accept-Language: "
$regexp = '/^([A-Za-z-]*):\s*/';
if (preg_match($regexp, $header, $matches)) {
$header = preg_replace($regexp, '', $header);
if (empty($field)) {
if (!empty($matches[1])) {
$field = strtolower($matches[1]);
} else {
$field = 'accept';
}
$field = preg_replace('/^accept-?/', '', $field);
}
if (empty($header) && $field === 'encoding') {
$header = 'identity';
}
} else {
# Derive from $_SERVER if possible.
if (false !== ($key = array_search($orig_header, $_SERVER, true))) {
$field = strtolower($key);
$field = str_replace('http_accept_', '', $field);
if (empty($field)) {
$field = 'accept';
}
}
}
$values = preg_split("/\s*,\s*/", $header);
$parsed = array();
$index = 0;
foreach ($values as $value) {
$value = trim($value, '"\'');
$split = preg_split("/\s*;\s*/", $value);
$type = array_shift($split);
$format = "";
$quality = 1.0;
$major = $type;
$minor = "";
$params = array();
$wildcard = false;
$sep = 'language' === $field ? '-' : '/';
if (false !== strpos($type, $sep)) {
list ($major, $minor) = explode($sep, $type, 2);
}
if ($major === '*') {
$wildcard = true;
}
# Pull out `format` e.g. +xml
if (false !== strpos($minor, '+')) {
$format = ltrim(strstr($minor, '+'), '+');
}
while (sizeof($split) > 0) {
$param = array_shift($split);
if (false === strpos($param, '=')) {
continue;
}
$paramName = strstr($param, '=', true);
$paramValue = ltrim(strstr($param, '='), '=');
if ($paramName === 'q') {
$quality = (float) $paramValue;
} else {
$params[$paramName] = trim($paramValue, '"\'');
}
}
$parsed[] = compact(
'field', 'value', 'type', 'format', 'quality',
'major', 'minor', 'wildcard', 'index', 'params'
);
$index += 1;
}
if (empty($parsed)) {
return $parsed;
}
usort($parsed, function ($a, $b) {
if ($a['quality'] === $b['quality']) {
return $a['index'] > $b['index'] ? 1 : -1;
} else {
return $a['quality'] < $b['quality'] ? 1 : -1;
}
});
return $parsed;
}
# ################### #
# ## Test ########### #
# ################### #
$headers = [
0 => "text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c",
1 => "text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1",
2 => "Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
3 => "text/css,*/*;q=0.1",
4 => "da, en-gb;q=0.8, en;q=0.7",
5 => "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
6 => "UTF-8,*;q=0.5",
7 => "Accept: audio/*; q=0.2, audio/basic",
8 => "gzip, deflate\t,sdch",
9 => 'Accept-Encoding: *',
10 => 'Accept-Encoding:',
11 => 'Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0',
12 => 'Accept-Charset:',
13 => 'fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4',
14 => '*;q=0.3,ISO-8859-1,utf-8;q=0.7',
15 => '*;q=0.3,ISO-8859-1;q=0.7,utf-8;q=0.7',
16 => '*;q=0.3,utf-8;q=0.7,ISO-8859-1;q=0.7',
17 => 'accept: application/vnd.github+json',
18 => 'Accept-Language: da, en-gb;q=0.8, en;q=0.7',
19 => 'Accept-Ranges: bytes',
20 => 'If-None-Match: "abcdefg12345678","apples"',
];
foreach($headers as $h) {
var_dump(parse_accept_header($h));
print '<HR>';
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment