Query.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  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,
  60. * PHP_QUERY_RFC3986 to encode using
  61. * RFC3986, or PHP_QUERY_RFC1738 to
  62. * encode using RFC1738.
  63. * @param bool $treatBoolsAsInts Set to true to encode as 0/1, and
  64. * false as false/true.
  65. */
  66. public static function build(array $params, $encoding = PHP_QUERY_RFC3986, bool $treatBoolsAsInts = true): string
  67. {
  68. if (!$params) {
  69. return '';
  70. }
  71. if ($encoding === false) {
  72. $encoder = function (string $str): string {
  73. return $str;
  74. };
  75. } elseif ($encoding === PHP_QUERY_RFC3986) {
  76. $encoder = 'rawurlencode';
  77. } elseif ($encoding === PHP_QUERY_RFC1738) {
  78. $encoder = 'urlencode';
  79. } else {
  80. throw new \InvalidArgumentException('Invalid type');
  81. }
  82. $castBool = $treatBoolsAsInts ? static function ($v) { return (int) $v; } : static function ($v) { return $v ? 'true' : 'false'; };
  83. $qs = '';
  84. foreach ($params as $k => $v) {
  85. $k = $encoder((string) $k);
  86. if (!is_array($v)) {
  87. $qs .= $k;
  88. $v = is_bool($v) ? $castBool($v) : $v;
  89. if ($v !== null) {
  90. $qs .= '='.$encoder((string) $v);
  91. }
  92. $qs .= '&';
  93. } else {
  94. foreach ($v as $vv) {
  95. $qs .= $k;
  96. $vv = is_bool($vv) ? $castBool($vv) : $vv;
  97. if ($vv !== null) {
  98. $qs .= '='.$encoder((string) $vv);
  99. }
  100. $qs .= '&';
  101. }
  102. }
  103. }
  104. return $qs ? (string) substr($qs, 0, -1) : '';
  105. }
  106. }