summaryrefslogtreecommitdiff
path: root/www/wiki/includes/libs/http/HttpAcceptParser.php
blob: df22b414f146db20c962061db479d6d6449a3188 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?php

/**
 * Utility for parsing a HTTP Accept header value into a weight map. May also be used with
 * other, similar headers like Accept-Language, Accept-Encoding, etc.
 *
 * @license GPL-2.0-or-later
 * @author Daniel Kinzler
 */

namespace Wikimedia\Http;

class HttpAcceptParser {

	/**
	 * Parses an HTTP header into a weight map, that is an associative array
	 * mapping values to their respective weights. Any header name preceding
	 * weight spec is ignored for convenience.
	 *
	 * This implementation is partially based on the code at
	 * http://www.thefutureoftheweb.com/blog/use-accept-language-header
	 *
	 * Note that type parameters and accept extension like the "level" parameter
	 * are not supported, weights are derived from "q" values only.
	 *
	 * @todo: If additional type parameters are present, ignore them cleanly.
	 *        At present, they often confuse the result.
	 *
	 * See HTTP/1.1 section 14 for details.
	 *
	 * @param string $rawHeader
	 *
	 * @return array
	 */
	public function parseWeights( $rawHeader ) {
		//FIXME: The code below was copied and adapted from WebRequest::getAcceptLang.
		//       Move this utility class into core for reuse!

		// first, strip header name
		$rawHeader = preg_replace( '/^[-\w]+:\s*/', '', $rawHeader );

		// Return values in lower case
		$rawHeader = strtolower( $rawHeader );

		// Break up string into pieces (values and q factors)
		$value_parse = null;
		preg_match_all( '@([a-z\d*]+([-+/.][a-z\d*]+)*)\s*(;\s*q\s*=\s*(1(\.0{0,3})?|0(\.\d{0,3})?)?)?@',
			$rawHeader, $value_parse );

		if ( !count( $value_parse[1] ) ) {
			return [];
		}

		$values = $value_parse[1];
		$qvalues = $value_parse[4];
		$indices = range( 0, count( $value_parse[1] ) - 1 );

		// Set default q factor to 1
		foreach ( $indices as $index ) {
			if ( $qvalues[$index] === '' ) {
				$qvalues[$index] = 1;
			} elseif ( $qvalues[$index] == 0 ) {
				unset( $values[$index], $qvalues[$index], $indices[$index] );
			} else {
				$qvalues[$index] = (float)$qvalues[$index];
			}
		}

		// Sort list. First by $qvalues, then by order. Reorder $values the same way
		array_multisort( $qvalues, SORT_DESC, SORT_NUMERIC, $indices, $values );

		// Create a list like "en" => 0.8
		$weights = array_combine( $values, $qvalues );

		return $weights;
	}

}