ApacheUrlMatcher.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Routing\Matcher;
  11. use Symfony\Component\Routing\Exception\MethodNotAllowedException;
  12. /**
  13. * ApacheUrlMatcher matches URL based on Apache mod_rewrite matching (see ApacheMatcherDumper).
  14. *
  15. * @author Fabien Potencier <fabien@symfony.com>
  16. * @author Arnaud Le Blanc <arnaud.lb@gmail.com>
  17. */
  18. class ApacheUrlMatcher extends UrlMatcher
  19. {
  20. /**
  21. * Tries to match a URL based on Apache mod_rewrite matching.
  22. *
  23. * Returns false if no route matches the URL.
  24. *
  25. * @param string $pathinfo The pathinfo to be parsed
  26. *
  27. * @return array An array of parameters
  28. *
  29. * @throws MethodNotAllowedException If the current method is not allowed
  30. */
  31. public function match($pathinfo)
  32. {
  33. $parameters = array();
  34. $defaults = array();
  35. $allow = array();
  36. $route = null;
  37. foreach ($this->denormalizeValues($_SERVER) as $key => $value) {
  38. $name = $key;
  39. // skip non-routing variables
  40. // this improves performance when $_SERVER contains many usual
  41. // variables like HTTP_*, DOCUMENT_ROOT, REQUEST_URI, ...
  42. if (false === strpos($name, '_ROUTING_')) {
  43. continue;
  44. }
  45. while (0 === strpos($name, 'REDIRECT_')) {
  46. $name = substr($name, 9);
  47. }
  48. // expect _ROUTING_<type>_<name>
  49. // or _ROUTING_<type>
  50. if (0 !== strpos($name, '_ROUTING_')) {
  51. continue;
  52. }
  53. if (false !== $pos = strpos($name, '_', 9)) {
  54. $type = substr($name, 9, $pos-9);
  55. $name = substr($name, $pos+1);
  56. } else {
  57. $type = substr($name, 9);
  58. }
  59. if ('param' === $type) {
  60. if ('' !== $value) {
  61. $parameters[$name] = $value;
  62. }
  63. } elseif ('default' === $type) {
  64. $defaults[$name] = $value;
  65. } elseif ('route' === $type) {
  66. $route = $value;
  67. } elseif ('allow' === $type) {
  68. $allow[] = $name;
  69. }
  70. unset($_SERVER[$key]);
  71. }
  72. if (null !== $route) {
  73. $parameters['_route'] = $route;
  74. return $this->mergeDefaults($parameters, $defaults);
  75. } elseif (0 < count($allow)) {
  76. throw new MethodNotAllowedException($allow);
  77. } else {
  78. return parent::match($pathinfo);
  79. }
  80. }
  81. /**
  82. * Denormalizes an array of values.
  83. *
  84. * @param string[] $values
  85. *
  86. * @return array
  87. */
  88. private function denormalizeValues(array $values)
  89. {
  90. $normalizedValues = array();
  91. foreach ($values as $key => $value) {
  92. if (preg_match('~^(.*)\[(\d+)\]$~', $key, $matches)) {
  93. if (!isset($normalizedValues[$matches[1]])) {
  94. $normalizedValues[$matches[1]] = array();
  95. }
  96. $normalizedValues[$matches[1]][(int) $matches[2]] = $value;
  97. } else {
  98. $normalizedValues[$key] = $value;
  99. }
  100. }
  101. return $normalizedValues;
  102. }
  103. }