UriFactory.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. <?php
  2. /**
  3. * @package Grav\Framework\Uri
  4. *
  5. * @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
  6. * @license MIT License; see LICENSE file for details.
  7. */
  8. namespace Grav\Framework\Uri;
  9. use InvalidArgumentException;
  10. use function is_string;
  11. /**
  12. * Class Uri
  13. * @package Grav\Framework\Uri
  14. */
  15. class UriFactory
  16. {
  17. /**
  18. * @param array $env
  19. * @return Uri
  20. * @throws InvalidArgumentException
  21. */
  22. public static function createFromEnvironment(array $env)
  23. {
  24. return new Uri(static::parseUrlFromEnvironment($env));
  25. }
  26. /**
  27. * @param string $uri
  28. * @return Uri
  29. * @throws InvalidArgumentException
  30. */
  31. public static function createFromString($uri)
  32. {
  33. return new Uri(static::parseUrl($uri));
  34. }
  35. /**
  36. * Creates a URI from a array of `parse_url()` components.
  37. *
  38. * @param array $parts
  39. * @return Uri
  40. * @throws InvalidArgumentException
  41. */
  42. public static function createFromParts(array $parts)
  43. {
  44. return new Uri($parts);
  45. }
  46. /**
  47. * @param array $env
  48. * @return array
  49. * @throws InvalidArgumentException
  50. */
  51. public static function parseUrlFromEnvironment(array $env)
  52. {
  53. // Build scheme.
  54. if (isset($env['REQUEST_SCHEME'])) {
  55. $scheme = strtolower($env['REQUEST_SCHEME']);
  56. } else {
  57. $https = $env['HTTPS'] ?? '';
  58. $scheme = (empty($https) || strtolower($https) === 'off') ? 'http' : 'https';
  59. }
  60. // Build user and password.
  61. $user = $env['PHP_AUTH_USER'] ?? '';
  62. $pass = $env['PHP_AUTH_PW'] ?? '';
  63. // Build host.
  64. $host = 'localhost';
  65. if (isset($env['HTTP_HOST'])) {
  66. $host = $env['HTTP_HOST'];
  67. } elseif (isset($env['SERVER_NAME'])) {
  68. $host = $env['SERVER_NAME'];
  69. }
  70. // Remove port from HTTP_HOST generated $hostname
  71. $host = explode(':', $host)[0];
  72. // Build port.
  73. $port = isset($env['SERVER_PORT']) ? (int)$env['SERVER_PORT'] : null;
  74. // Build path.
  75. $request_uri = $env['REQUEST_URI'] ?? '';
  76. $path = parse_url('http://example.com' . $request_uri, PHP_URL_PATH);
  77. // Build query string.
  78. $query = $env['QUERY_STRING'] ?? '';
  79. if ($query === '') {
  80. $query = parse_url('http://example.com' . $request_uri, PHP_URL_QUERY);
  81. }
  82. // Support ngnix routes.
  83. if (strpos((string) $query, '_url=') === 0) {
  84. parse_str($query, $q);
  85. unset($q['_url']);
  86. $query = http_build_query($q);
  87. }
  88. return [
  89. 'scheme' => $scheme,
  90. 'user' => $user,
  91. 'pass' => $pass,
  92. 'host' => $host,
  93. 'port' => $port,
  94. 'path' => $path,
  95. 'query' => $query
  96. ];
  97. }
  98. /**
  99. * UTF-8 aware parse_url() implementation.
  100. *
  101. * @param string $url
  102. * @return array
  103. * @throws InvalidArgumentException
  104. */
  105. public static function parseUrl($url)
  106. {
  107. if (!is_string($url)) {
  108. throw new InvalidArgumentException('URL must be a string');
  109. }
  110. $encodedUrl = preg_replace_callback(
  111. '%[^:/@?&=#]+%u',
  112. static function ($matches) {
  113. return rawurlencode($matches[0]);
  114. },
  115. $url
  116. );
  117. $parts = is_string($encodedUrl) ? parse_url($encodedUrl) : false;
  118. if ($parts === false) {
  119. throw new InvalidArgumentException("Malformed URL: {$url}");
  120. }
  121. return $parts;
  122. }
  123. /**
  124. * Parse query string and return it as an array.
  125. *
  126. * @param string $query
  127. * @return mixed
  128. */
  129. public static function parseQuery($query)
  130. {
  131. parse_str($query, $params);
  132. return $params;
  133. }
  134. /**
  135. * Build query string from variables.
  136. *
  137. * @param array $params
  138. * @return string
  139. */
  140. public static function buildQuery(array $params)
  141. {
  142. if (!$params) {
  143. return '';
  144. }
  145. $separator = ini_get('arg_separator.output') ?: '&';
  146. return http_build_query($params, '', $separator, PHP_QUERY_RFC3986);
  147. }
  148. }