HttpAcceptParser.php 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. <?php
  2. /**
  3. * Utility for parsing a HTTP Accept header value into a weight map. May also be used with
  4. * other, similar headers like Accept-Language, Accept-Encoding, etc.
  5. *
  6. * @license GPL-2.0-or-later
  7. * @author Daniel Kinzler
  8. */
  9. namespace Wikimedia\Http;
  10. class HttpAcceptParser {
  11. /**
  12. * Parses an HTTP header into a weight map, that is an associative array
  13. * mapping values to their respective weights. Any header name preceding
  14. * weight spec is ignored for convenience.
  15. *
  16. * This implementation is partially based on the code at
  17. * http://www.thefutureoftheweb.com/blog/use-accept-language-header
  18. *
  19. * Note that type parameters and accept extension like the "level" parameter
  20. * are not supported, weights are derived from "q" values only.
  21. *
  22. * @todo If additional type parameters are present, ignore them cleanly.
  23. * At present, they often confuse the result.
  24. *
  25. * See HTTP/1.1 section 14 for details.
  26. *
  27. * @param string $rawHeader
  28. *
  29. * @return array
  30. */
  31. public function parseWeights( $rawHeader ) {
  32. //FIXME: The code below was copied and adapted from WebRequest::getAcceptLang.
  33. // Move this utility class into core for reuse!
  34. // first, strip header name
  35. $rawHeader = preg_replace( '/^[-\w]+:\s*/', '', $rawHeader );
  36. // Return values in lower case
  37. $rawHeader = strtolower( $rawHeader );
  38. // Break up string into pieces (values and q factors)
  39. $value_parse = null;
  40. preg_match_all( '@([a-z\d*]+([-+/.][a-z\d*]+)*)\s*(;\s*q\s*=\s*(1(\.0{0,3})?|0(\.\d{0,3})?)?)?@',
  41. $rawHeader, $value_parse );
  42. if ( !count( $value_parse[1] ) ) {
  43. return [];
  44. }
  45. $values = $value_parse[1];
  46. $qvalues = $value_parse[4];
  47. $indices = range( 0, count( $value_parse[1] ) - 1 );
  48. // Set default q factor to 1
  49. foreach ( $indices as $index ) {
  50. if ( $qvalues[$index] === '' ) {
  51. $qvalues[$index] = 1;
  52. } elseif ( $qvalues[$index] == 0 ) {
  53. unset( $values[$index], $qvalues[$index], $indices[$index] );
  54. } else {
  55. $qvalues[$index] = (float)$qvalues[$index];
  56. }
  57. }
  58. // Sort list. First by $qvalues, then by order. Reorder $values the same way
  59. array_multisort( $qvalues, SORT_DESC, SORT_NUMERIC, $indices, $values );
  60. // Create a list like "en" => 0.8
  61. $weights = array_combine( $values, $qvalues );
  62. return $weights;
  63. }
  64. }