Query.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. <?php
  2. declare(strict_types=1);
  3. namespace GuzzleHttp\Psr7;
  4. final class Query
  5. {
  6. /**
  7. * Parse a query string into an associative array.
  8. *
  9. * If multiple values are found for the same key, the value of that key
  10. * value pair will become an array. This function does not parse nested
  11. * PHP style arrays into an associative array (e.g., `foo[a]=1&foo[b]=2`
  12. * will be parsed into `['foo[a]' => '1', 'foo[b]' => '2'])`.
  13. *
  14. * @param string $str Query string to parse
  15. * @param int|bool $urlEncoding How the query string is encoded
  16. */
  17. public static function parse(string $str, $urlEncoding = true): array
  18. {
  19. $result = [];
  20. if ($str === '') {
  21. return $result;
  22. }
  23. if ($urlEncoding === true) {
  24. $decoder = function ($value) {
  25. return rawurldecode(str_replace('+', ' ', (string) $value));
  26. };
  27. } elseif ($urlEncoding === PHP_QUERY_RFC3986) {
  28. $decoder = 'rawurldecode';
  29. } elseif ($urlEncoding === PHP_QUERY_RFC1738) {
  30. $decoder = 'urldecode';
  31. } else {
  32. $decoder = function ($str) {
  33. return $str;
  34. };
  35. }
  36. foreach (explode('&', $str) as $kvp) {
  37. $parts = explode('=', $kvp, 2);
  38. $key = $decoder($parts[0]);
  39. $value = isset($parts[1]) ? $decoder($parts[1]) : null;
  40. if (!array_key_exists($key, $result)) {
  41. $result[$key] = $value;
  42. } else {
  43. if (!is_array($result[$key])) {
  44. $result[$key] = [$result[$key]];
  45. }
  46. $result[$key][] = $value;
  47. }
  48. }
  49. return $result;
  50. }
  51. /**
  52. * Build a query string from an array of key value pairs.
  53. *
  54. * This function can use the return value of `parse()` to build a query
  55. * string. This function does not modify the provided keys when an array is
  56. * encountered (like `http_build_query()` would).
  57. *
  58. * @param array $params Query string parameters.
  59. * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
  60. * to encode using RFC3986, or PHP_QUERY_RFC1738
  61. * to encode using RFC1738.
  62. */
  63. public static function build(array $params, $encoding = PHP_QUERY_RFC3986): string
  64. {
  65. if (!$params) {
  66. return '';
  67. }
  68. if ($encoding === false) {
  69. $encoder = function (string $str): string {
  70. return $str;
  71. };
  72. } elseif ($encoding === PHP_QUERY_RFC3986) {
  73. $encoder = 'rawurlencode';
  74. } elseif ($encoding === PHP_QUERY_RFC1738) {
  75. $encoder = 'urlencode';
  76. } else {
  77. throw new \InvalidArgumentException('Invalid type');
  78. }
  79. $qs = '';
  80. foreach ($params as $k => $v) {
  81. $k = $encoder((string) $k);
  82. if (!is_array($v)) {
  83. $qs .= $k;
  84. $v = is_bool($v) ? (int) $v : $v;
  85. if ($v !== null) {
  86. $qs .= '=' . $encoder((string) $v);
  87. }
  88. $qs .= '&';
  89. } else {
  90. foreach ($v as $vv) {
  91. $qs .= $k;
  92. $vv = is_bool($vv) ? (int) $vv : $vv;
  93. if ($vv !== null) {
  94. $qs .= '=' . $encoder((string) $vv);
  95. }
  96. $qs .= '&';
  97. }
  98. }
  99. }
  100. return $qs ? (string) substr($qs, 0, -1) : '';
  101. }
  102. }