2009-06-26 10 views
17

私はブラウザのサポートによってXHTML 1.1をapplication/xhtml + xmlまたはHTML 4.01をtext/htmlとして提供する標準準拠のウェブサイトフレームワークを構築しようとしています。現在のところ、acceptヘッダーのどこでも "application/xhtml + xml"を探し、それが存在する場合はそれを使用しますが、柔軟性がありません。text/htmlの方がスコアが高くなる可能性があります。また、他のフォーマット(WAP、SVG、XFormsなど)を追加すると、より複雑になります。だから、誰かが試してテストしたPHPコードを、サーバーから与えられた文字列配列から選択することを知っていますか?それとも、クライアントのスコアに基づいて順序付けされたリストをサポートしていますか?HTTPからコンテンツタイプを選択するには

+0

それは準拠しており、「正しいことを行う」の基準を試してみて、あることを、すべての良いですが、私はあなたが実際にから任意の利益を得ることがあれば、それは考慮瞬間を費やす価値があると思いますこのすべて。例えば。 text/htmlがうまくいけばapplication/xhtml + xmlを提供する理由はあまりありません。 –

答えて

11

apache's mod_negotiation moduleを利用できます。この方法では、独自のプリファレンス(コンテンツタイプ(e、g、「クライアントが非常に多くのことを好まない限り、アプリケーション/ xhtml + xmlを配信したいと思っています)を含む、モジュールが提供するすべてのネゴシエーション機能を使用できます。 ")。 基本的なソリューション:

  • が内容として
    <?php 
    echo 'selected type: ', substr($_SERVER['PATH_INFO'], 1);
    でファイルfoo.phpを作成
    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
  • 内容として持つファイルfoo.varを作成
    AddHandler type-map .var
  • 内容としてで.htaccessファイルを作成します。
  • あなたはmod_negotiationはのAddHandlerとAcceptPathInfoのための適切なAllowOverrideの権限は$ _SERVER [ 'PATH_INFO']で無効にされていない、有効にする必要があります。これが機能するために要求http://localhost/whatever/foo.var


私のFirefoxが "Accept:text/html、application/xhtml + xml、application/xml; q = 0.9,/; q = 0.8"を送信し、例の.varマップが "selected type:xhtml" 。
PATH_INFOを取り除くために、またはfoo .varをリクエストする必要がありますが、基本的な考え方は次のとおりです:mod_negotiationがリクエストをあなたのPHPスクリプトにリダイレクトして、選択されたコンテンツタイプ。

だから、誰もがそれは純粋なPHPソリューションではありません
を選択するために、PHPコードの実証済みの作品を知っているんが、私はmod_negotiationが試みられていると言うだろうし、念のため;-)

+0

- PHPよりも優れています。 – l0b0

+3

私はこのロジックを自分のコードの中に保存したいと思っています。 – Greg

19

リトルスニペット:

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; 
} 

使用例:

$mime = getBestSupportedMimeType(Array ('application/xhtml+xml', 'text/html')); 
+0

ほんの少しの改善です:関数プロトタイプを 'function getBestSupportedMimeType($ mimeTypes = null、$ acceptedTypes = FALSE)に変更してください。{if($ acceptedTypes === FALSE){$ acceptedTypes = $ _SERVER ['HTTP_ACCEPT']; } ... '。基本的にカスタム受付タイプを許可するのは、プログラムがもう少しカスタムを行う必要がある場合です。 – chacham15

10

PEAR :: HTTP 1.4.1が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"; 
} 

プリント

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

編集方法を持っていますこれはあまりにも良くないかもしれません...
私のFirefoxは受け入れ を送信します:text/htmlのを、アプリケーション/ XHTML + xmlの、アプリケーション/ XMLを、Q = 0.9、/; qは= 0.8
テキスト/ htmlとアプリケーション/ XHTML + xmlのQ = 1.0を持っていますが、 PEAR :: HTTP(afaik)は、 があなたが好むものを選ぶことはできません。あなたが渡したものが$ supportとして渡されてもtext/htmlを返します。これはあなたには十分かもしれません。私の他の答えを見てください。

+1

PHP 5コードの場合、HTTP2パッケージを使用してください:http://pear.php.net/package/HTTP2 – cweiske

9

をテスト、Negotiationは、コンテンツネゴシエーションを処理するための純粋なPHP実装です。

1

私の問題を修正し改善した@ maciej-Łebkowskiと@ chacham15ソリューションをマージしました。 $desiredTypes = 'text/*'Acceptを渡した場合、text/html;q=1を含む場合は、text/htmlが返されます。

/** 
* 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; 
} 
+1

クライアントのAcceptヘッダーからq = 0を除外してはなりません。これは、クライアントがそのタイプを受け入れないことを意味します。 'Accept-Language:en、en-US; q = 0'は、アメリカ人でない限り英語を受け入れることを意味します。 –

0

クライアントは、応答でmime-typeのリストを受け入れることができます。一方、応答の順序はクライアント側にとって非常に重要です。 PHP Pear HTTP2は、言語、文字セット、およびMIMEタイプを処理するのに最適です。ここで

$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"; 
} 

良いチュートリアルです:https://cweiske.de/tagebuch/php-http-negotiation.htm

関連する問題