Ich versuche, ein standardkonformes Website-Framework zu erstellen, das XHTML 1.1 als application/xhtml + xml oder HTML 4.01 als text/html je nach Browserunterstützung anbietet. Momentan sucht es einfach nach "application/xhtml + xml" irgendwo im accept-Header und benutzt das, wenn es existiert, aber das ist nicht flexibel - text/html könnte eine höhere Punktzahl haben. Außerdem wird es komplexer, wenn andere Formate (WAP, SVG, XForms usw.) hinzugefügt werden. Kennt also jemand ein erprobtes Stück PHP-Code, um aus einem String-Array, das vom Server bereitgestellt wird, entweder das vom Client am besten unterstützte oder eine geordnete Liste basierend auf dem Client-Score auszuwählen?So wählen Sie den Inhaltstyp aus HTTP Akzeptieren Header in PHP
Antwort
Sie können apache's mod_negotiation module nutzen. Auf diese Weise können Sie die volle Bandbreite an Verhandlungsfunktionen des Moduls nutzen, einschließlich Ihrer eigenen Einstellungen für den Inhaltstyp (zB "Ich möchte wirklich application/xhtml + xml bereitstellen, es sei denn, der Kunde bevorzugt etwas anderes "). Basislösung:
- erstellen eine .htaccess Datei mit
AddHandler type-map .var
als Inhalt - eine Datei foo.var erstellen mit
URI: foo
als Inhalt
URI: foo.php/html Content-type: text/html; qs=0.7
URI: foo.php/xhtml Content-type: application/xhtml+xml; qs=0.8 - eine Datei foo.php mit
<?php echo 'selected type: ', substr($_SERVER['PATH_INFO'], 1);
als Inhalt erstellen. http://localhost/whatever/foo.var - Anfrage
Damit dies funktioniert Sie mod_negotiation aktiviert, werden die entsprechenden AllowOverride Privilegien für AddHandler und AcceptPathInfo nicht deaktiviert wird für $ _SERVER [ 'PATH_INFO'] müssen.
Mit meinem Firefox senden "Akzeptieren: text/html, application/xhtml + xml, application/xml; q = 0.9, /; q = 0.8" und das Beispiel .var map das Ergebnis ist "ausgewählter Typ: xhtml" .
Sie können andere "Tweaks" verwenden, um PATH_INFO oder die Anforderung von foo .var loszuwerden, aber das Grundkonzept lautet: Lassen Sie mod_nevertiation die Anfrage so an Ihr PHP-Skript umleiten, dass das Skript "lesen" kann der ausgewählte Inhaltstyp
So, weiß jemand von einem bewährten Stück Code PHPauswählen Es ist nicht eine reine PHP-Lösung, aber ich würde sagen, mod_negotiation wurde versucht und getestet ;-)
http://www.dev-archive.net/articles/xhtml.html#content-negotiation ist in Perl geschrieben, aber es ist übersichtlich und besteht nur aus einigen If/Else und Regex. Die Portierung auf PHP sollte trivial sein.
Kleiner Ausschnitt aus meiner Bibliothek:
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;
}
Beispiel Nutzung:
$mime = getBestSupportedMimeType(Array ('application/xhtml+xml', 'text/html'));
nur eine kleine Verbesserung: Ändern Sie den Funktionsprototyp in 'function getBestSupportedMimeType ($ mimeTypes = null, $ acceptedTypes = FALSE) {if ($ acceptedTypes === FALSE) {$ acceptedTypes = $ _SERVER ['HTTP_ACCEPT']; } ... '. Im Wesentlichen erlauben benutzerdefinierte Typen akzeptieren, wenn das Programm etwas mehr benutzerdefinierte tun muss. – chacham15
Birne :: HTTP 1.4.1 hat ein Verfahren string negotiateMimeType(array $supported, string $default)
<?php
require 'HTTP.php';
foreach(
array(
'text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5',
'text/*;q=0.3, text/html;q=0.8, application/xhtml+xml;q=0.7, */*;q=0.2',
'text/*;q=0.3, text/html;q=0.7, */*;q=0.8',
'text/*, application/xhtml+xml',
'text/html, application/xhtml+xml'
) as $testheader) {
$_SERVER['HTTP_ACCEPT'] = $testheader;
$http = new HTTP;
echo $testheader, ' -> ',
$http->negotiateMimeType(array('application/xhtml+xml', 'text/html'), 'application/xhtml+xml'),
"\n";
}
druckt
text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, /;q=0.5 -> application/xhtml+xml text/*;q=0.3, text/html;q=0.8, application/xhtml+xml;q=0.7, */*;q=0.2 -> text/html text/*;q=0.3, text/html;q=0.7, */*;q=0.8 -> application/xhtml+xml text/*, application/xhtml+xml -> application/xhtml+xml text/html, application/xhtml+xml -> text/html
bearbeiten : das könnte doch nicht so gut sein ...
My firefox sendet Accept: text/html, application/XHTML + xml, application/xml; q = 0,9, /; q = 0,8
text/html und application/XHTML + xml haben q = 1,0, aber PEAR :: HTTP (afaik) lässt nicht Sie wählen Sie, welche Sie bevorzugen, es gibt Text/HTML zurück, egal was Sie als $ unterstützt übergeben. Dies kann oder kann nicht für Sie ausreichend sein. Siehe meine anderen Antworten.
Für PHP 5-Code verwenden Sie das HTTP2-Paket: http://pear.php.net/package/HTTP2 – cweiske
Nur für das Protokoll Negotiation ist eine reine PHP-Implementierung für die Inhaltsverhandlung.
Zusammengeführt @ maciej-Łebkowski und @ chacham15 Lösungen mit meinen Problemen behoben und Verbesserungen. Wenn Sie $desiredTypes = 'text/*'
übergeben und Accept
text/html;q=1
enthält, wird text/html
zurückgegeben.
/**
* Parse, sort and select best Content-type, supported by a user browser.
*
* @param string|string[] $desiredTypes The filter of desired types. If &null then the all supported types will returned.
* @param string $acceptRules Supported types in the HTTP Accept header format. $_SERVER['HTTP_ACCEPT'] by default.
* @return string|string[]|null Matched by $desiredTypes type or all accepted types.
* @link Inspired by http://stackoverflow.com/a/1087498/3155344
*/
function resolveContentNegotiation($desiredTypes = null, $acceptRules = null)
{
if (!$acceptRules) {
$acceptRules = @$_SERVER['HTTP_ACCEPT'];
}
// Accept header is case insensitive, and whitespace isn't important.
$acceptRules = strtolower(str_replace(' ', '', $acceptRules));
$sortedAcceptTypes = array();
foreach (explode(',', $acceptRules) as $acceptRule) {
$q = 1; // the default accept quality (rating).
// Check if there is a different quality.
if (strpos($acceptRule, ';q=') !== false) {
// Divide "type;q=X" into two parts: "type" and "X"
list($acceptRule, $q) = explode(';q=', $acceptRule, 2);
}
$sortedAcceptTypes[$acceptRule] = $q;
}
// WARNING: zero quality is means, that type isn't supported! Thus remove them.
$sortedAcceptTypes = array_filter($sortedAcceptTypes);
arsort($sortedAcceptTypes, SORT_NUMERIC);
// If no parameter was passed, just return parsed data.
if (!$desiredTypes) {
return $sortedAcceptTypes;
}
$desiredTypes = array_map('strtolower', (array) $desiredTypes);
// Let's check our supported types.
foreach (array_keys($sortedAcceptTypes) as $type) {
foreach ($desiredTypes as $desired) {
if (fnmatch($desired, $type)) {
return $type;
}
}
}
// No matched type.
return null;
}
Sie dürfen q = 0 aus den Accept-Kopfzeilen des Clients nicht herausfiltern. Dies bedeutet, dass der Client diesen Typ nicht akzeptiert, z. "Accept-Language: en, en-US; q = 0" bedeutet, dass ich kein Englisch akzeptieren werde, solange es nicht amerikanisch ist. –
PEAR's HTTP2 library unterstützt alle Arten von Accept
Header-Parsing. Es ist über composer und PEAR installierbar.
Beispiele finden Sie unter documentation oder my blog post.
Der Client akzeptiert möglicherweise eine Liste der MIME-Typen in der Antwort. Auf der anderen Seite ist die Reihenfolge der Antwort sehr wichtig für die Kundenseite. PHP Pear HTTP2 ist das beste, um mit Sprache, Zeichensatz und MIME-Typen umzugehen.
$http = new HTTP2();
$supportedTypes = array(
'text/html',
'application/json'
);
$type = $http->negotiateMimeType($supportedTypes, false);
if ($type === false) {
header('HTTP/1.1 406 Not Acceptable');
echo "You don't want any of the content types I have to offer\n";
} else {
echo 'I\'d give you data of type: ' . $type . "\n";
}
ist hier ein gutes Tutorial: https://cweiske.de/tagebuch/php-http-negotiation.htm
Während es alles gut zu versuchen und sein Standards kompatibel und ist „Dinge richtig tun“, ich denke, es lohnt sich in Anbetracht einen Moment Zeit zu verbringen, wenn Sie irgendwelche Vorteile gewinnen tatsächlich aus all das. Z.B. nicht gerade ein Grund, um application/xhtml + xml zu liefern, wenn text/html gut funktioniert und so weiter. –