Url.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * The Minz_Url class handles URLs across the MINZ framework
  5. */
  6. class Minz_Url {
  7. /**
  8. * Display a formatted URL
  9. * @param string|array{c?:string,a?:string,params?:array<string,mixed>} $url The URL to format, defined as an array:
  10. * $url['c'] = controller
  11. * $url['a'] = action
  12. * $url['params'] = array of additional parameters
  13. * or as a string
  14. * @param string $encoding how to encode & (& ou &amp; pour html)
  15. * @param array{c?:string,a?:string,params?:array<string,mixed>} $amend Parameters to add or replace in the URL in its array form
  16. * @return string Formatted URL
  17. * @throws Minz_ConfigurationException
  18. */
  19. public static function display(string|array $url = [], string $encoding = 'html', bool|string $absolute = false, array $amend = []): string {
  20. $isArray = is_array($url);
  21. if ($isArray) {
  22. if (!empty($amend)) {
  23. /** @var array{c?:string,a?:string,params?:array<string,mixed>} $url */
  24. $url = array_replace_recursive($url, $amend);
  25. }
  26. $url = self::checkControllerUrl($url);
  27. }
  28. $url_string = '';
  29. if ($absolute !== false) {
  30. $url_string = Minz_Request::getBaseUrl();
  31. if (strlen($url_string) < strlen('http://a.bc')) {
  32. $url_string = Minz_Request::guessBaseUrl();
  33. if (PUBLIC_RELATIVE === '..' && preg_match('%' . PUBLIC_TO_INDEX_PATH . '(/|$)%', $url_string)) {
  34. //TODO: Implement proper resolver of relative parts such as /test/./../
  35. $url_string = dirname($url_string);
  36. }
  37. }
  38. if ($isArray) {
  39. $url_string .= PUBLIC_TO_INDEX_PATH;
  40. }
  41. if ($absolute === 'root') {
  42. $url_string = parse_url($url_string, PHP_URL_PATH);
  43. }
  44. } else {
  45. $url_string = $isArray ? '.' : PUBLIC_RELATIVE;
  46. }
  47. if ($isArray) {
  48. $url_string .= '/' . self::printUri($url, $encoding);
  49. } elseif ($encoding === 'html') {
  50. $url_string = Minz_Helper::htmlspecialchars_utf8($url_string . $url);
  51. } else {
  52. $url_string .= $url;
  53. }
  54. return $url_string;
  55. }
  56. /**
  57. * Construit l'URI d'une URL
  58. * @param array{c:string,a:string,params:array<string,mixed>} $url URL as array definition
  59. * @param string $encodage pour indiquer comment encoder les & (& ou &amp; pour html)
  60. * @return string uri sous la forme ?key=value&key2=value2
  61. */
  62. private static function printUri(array $url, string $encodage): string {
  63. $uri = '';
  64. $separator = '?';
  65. $anchor = '';
  66. if ($encodage === 'html') {
  67. $and = '&amp;';
  68. } else {
  69. $and = '&';
  70. }
  71. if (!empty($url['params']) && is_array($url['params']) && !empty($url['params']['#'])) {
  72. if (is_string($url['params']['#'])) {
  73. $anchor = '#' . ($encodage === 'html' ? htmlspecialchars($url['params']['#'], ENT_QUOTES, 'UTF-8') : $url['params']['#']);
  74. }
  75. unset($url['params']['#']);
  76. }
  77. if (isset($url['c']) && is_string($url['c'])
  78. && $url['c'] != Minz_Request::defaultControllerName()) {
  79. $uri .= $separator . 'c=' . $url['c'];
  80. $separator = $and;
  81. }
  82. if (isset($url['a']) && is_string($url['a'])
  83. && $url['a'] != Minz_Request::defaultActionName()) {
  84. $uri .= $separator . 'a=' . $url['a'];
  85. $separator = $and;
  86. }
  87. if (isset($url['params']) && is_array($url['params'])) {
  88. unset($url['params']['c']);
  89. unset($url['params']['a']);
  90. foreach ($url['params'] as $key => $param) {
  91. if (!is_string($key) || (!is_string($param) && !is_int($param) && !is_bool($param))) {
  92. continue;
  93. }
  94. $uri .= $separator . urlencode($key) . '=' . urlencode((string)$param);
  95. $separator = $and;
  96. }
  97. }
  98. $uri .= $anchor;
  99. return $uri;
  100. }
  101. /**
  102. * Check that all array elements representing the controller URL are OK
  103. * @param array{c?:string,a?:string,params?:array<string,mixed>} $url controller URL as array
  104. * @return array{c:string,a:string,params:array<string,mixed>} Verified controller URL as array
  105. */
  106. public static function checkControllerUrl(array $url): array {
  107. return [
  108. 'c' => empty($url['c']) || !is_string($url['c']) ? Minz_Request::defaultControllerName() : $url['c'],
  109. 'a' => empty($url['a']) || !is_string($url['a']) ? Minz_Request::defaultActionName() : $url['a'],
  110. 'params' => empty($url['params']) || !is_array($url['params']) ? [] : $url['params'],
  111. ];
  112. }
  113. /** @param array{c?:string,a?:string,params?:array<string,mixed>} $url */
  114. public static function serialize(?array $url = []): string {
  115. if (empty($url)) {
  116. return '';
  117. }
  118. try {
  119. return base64_encode(json_encode($url, JSON_THROW_ON_ERROR));
  120. } catch (\Throwable $exception) {
  121. return '';
  122. }
  123. }
  124. /** @return array{c?:string,a?:string,params?:array<string,mixed>} */
  125. public static function unserialize(string $url = ''): array {
  126. $result = json_decode(base64_decode($url, true) ?: '', true, JSON_THROW_ON_ERROR) ?? [];
  127. /** @var array{c?:string,a?:string,params?:array<string,mixed>} $result */
  128. return $result;
  129. }
  130. /**
  131. * Returns an array representing the URL as passed in the address bar
  132. * @return array{c?:string,a?:string,params?:array<string,string>} URL representation
  133. */
  134. public static function build(): array {
  135. $get = [];
  136. foreach ($_GET as $key => $value) {
  137. if (is_string($key) && is_string($value)) {
  138. $get[$key] = $value;
  139. }
  140. }
  141. $url = [
  142. 'c' => is_string($_GET['c'] ?? null) ? $_GET['c'] : Minz_Request::defaultControllerName(),
  143. 'a' => is_string($_GET['a'] ?? null) ? $_GET['a'] : Minz_Request::defaultActionName(),
  144. 'params' => $get,
  145. ];
  146. // post-traitement
  147. unset($url['params']['c']);
  148. unset($url['params']['a']);
  149. return $url;
  150. }
  151. }
  152. function _url(string $controller, string $action, int|string ...$args): string {
  153. $nb_args = count($args);
  154. if ($nb_args % 2 !== 0) {
  155. return '';
  156. }
  157. $params = [];
  158. for ($i = 0; $i < $nb_args; $i += 2) {
  159. $arg = '' . $args[$i];
  160. $params[$arg] = '' . $args[$i + 1];
  161. }
  162. return Minz_Url::display(['c' => $controller, 'a' => $action, 'params' => $params]);
  163. }