diff --git a/lib/Cake/Network/CakeRequest.php b/lib/Cake/Network/CakeRequest.php index 213d84bef..983db7f32 100644 --- a/lib/Cake/Network/CakeRequest.php +++ b/lib/Cake/Network/CakeRequest.php @@ -613,29 +613,49 @@ class CakeRequest implements ArrayAccess { * provided type. */ public function accepts($type = null) { + $raw = $this->parseAccept(); $accept = array(); - $header = explode(',', $this->header('accept')); - foreach (array_filter(array_reverse($header)) as $value) { - $prefPos = strpos($value, ';'); - if ($prefPos !== false) { - $prefValue = (float) substr($value, strpos($value, '=') + 1); - $value = trim(substr($value, 0, $prefPos)); - } else { - $prefValue = 1.0; - $value = trim($value); - } - if ($prefValue) { - $accept[$value] = $prefValue; - } + foreach ($raw as $value => $types) { + $accept = array_merge($accept, $types); } - arsort($accept); - $accept = array_keys($accept); if ($type === null) { return $accept; } return in_array($type, $accept); } +/** + * Parse the HTTP_ACCEPT header and return a sorted array with content types + * as the keys, and pref values as the values. + * + * Generally you want to use CakeRequest::accept() to get a simple list + * of the accepted content types. + * + * @return array An array of prefValue => array(content/types) + */ + public function parseAccept() { + $accept = array(); + $header = explode(',', $this->header('accept')); + foreach (array_filter($header) as $value) { + $prefPos = strpos($value, ';'); + if ($prefPos !== false) { + $prefValue = substr($value, strpos($value, '=') + 1); + $value = trim(substr($value, 0, $prefPos)); + } else { + $prefValue = '1.0'; + $value = trim($value); + } + if (!isset($accept[$prefValue])) { + $accept[$prefValue] = array(); + } + if ($prefValue) { + $accept[$prefValue][] = $value; + } + } + krsort($accept); + return $accept; + } + /** * Get the lanaguages accepted by the client, or check if a specific language is accepted. * diff --git a/lib/Cake/Test/Case/Network/CakeRequestTest.php b/lib/Cake/Test/Case/Network/CakeRequestTest.php index f89ef7625..c8b3b0e3d 100644 --- a/lib/Cake/Test/Case/Network/CakeRequestTest.php +++ b/lib/Cake/Test/Case/Network/CakeRequestTest.php @@ -785,7 +785,7 @@ class CakeRequestTestCase extends CakeTestCase { $result = $request->accepts(); $expected = array( - 'text/xml', 'application/xhtml+xml', 'text/html', 'image/png', 'text/plain', 'application/xml' + 'text/xml', 'application/xhtml+xml', 'text/html', 'text/plain', 'image/png', 'application/xml' ); $this->assertEquals($expected, $result, 'Content types differ.'); @@ -826,6 +826,23 @@ class CakeRequestTestCase extends CakeTestCase { $this->assertEquals($expected, $result); } +/** + * Test the raw parsing of accept headers into the q value formatting. + * + * @return void + */ + public function testParseAcceptWithQValue() { + $_SERVER['HTTP_ACCEPT'] = 'text/html;q=0.8,application/json;q=0.7,application/xml;q=1.0,image/png'; + $request = new CakeRequest('/', false); + $result = $request->parseAccept(); + $expected = array( + '1.0' => array('application/xml', 'image/png'), + '0.8' => array('text/html'), + '0.7' => array('application/json'), + ); + $this->assertEquals($expected, $result); + } + /** * testBaseUrlAndWebrootWithModRewrite method *