|
1 <?php |
|
2 |
|
3 /* |
|
4 * This file is part of the Symfony package. |
|
5 * |
|
6 * (c) Fabien Potencier <fabien@symfony.com> |
|
7 * |
|
8 * For the full copyright and license information, please view the LICENSE |
|
9 * file that was distributed with this source code. |
|
10 */ |
|
11 |
|
12 namespace Symfony\Component\Routing\Matcher\Dumper; |
|
13 |
|
14 use Symfony\Component\Routing\Route; |
|
15 |
|
16 /** |
|
17 * Dumps a set of Apache mod_rewrite rules. |
|
18 * |
|
19 * @author Fabien Potencier <fabien@symfony.com> |
|
20 * @author Kris Wallsmith <kris@symfony.com> |
|
21 */ |
|
22 class ApacheMatcherDumper extends MatcherDumper |
|
23 { |
|
24 /** |
|
25 * Dumps a set of Apache mod_rewrite rules. |
|
26 * |
|
27 * Available options: |
|
28 * |
|
29 * * script_name: The script name (app.php by default) |
|
30 * * base_uri: The base URI ("" by default) |
|
31 * |
|
32 * @param array $options An array of options |
|
33 * |
|
34 * @return string A string to be used as Apache rewrite rules |
|
35 */ |
|
36 public function dump(array $options = array()) |
|
37 { |
|
38 $options = array_merge(array( |
|
39 'script_name' => 'app.php', |
|
40 'base_uri' => '', |
|
41 ), $options); |
|
42 |
|
43 $rules = array("# skip \"real\" requests\nRewriteCond %{REQUEST_FILENAME} -f\nRewriteRule .* - [QSA,L]"); |
|
44 $methodVars = array(); |
|
45 |
|
46 foreach ($this->getRoutes()->all() as $name => $route) { |
|
47 $compiledRoute = $route->compile(); |
|
48 |
|
49 // prepare the apache regex |
|
50 $regex = preg_replace('/\?P<.+?>/', '', substr(str_replace(array("\n", ' '), '', $compiledRoute->getRegex()), 1, -2)); |
|
51 $regex = '^'.preg_quote($options['base_uri']).substr($regex, 1); |
|
52 |
|
53 $hasTrailingSlash = '/$' == substr($regex, -2) && '^/$' != $regex; |
|
54 |
|
55 $variables = array('E=_ROUTING__route:'.$name); |
|
56 foreach ($compiledRoute->getVariables() as $i => $variable) { |
|
57 $variables[] = 'E=_ROUTING_'.$variable.':%'.($i + 1); |
|
58 } |
|
59 foreach ($route->getDefaults() as $key => $value) { |
|
60 // todo: a more legit way to escape the value? |
|
61 $variables[] = 'E=_ROUTING_'.$key.':'.strtr($value, array( |
|
62 ':' => '\\:', |
|
63 '=' => '\\=', |
|
64 '\\' => '\\\\', |
|
65 ' ' => '\\ ', |
|
66 )); |
|
67 } |
|
68 $variables = implode(',', $variables); |
|
69 |
|
70 $rule = array("# $name"); |
|
71 |
|
72 // method mismatch |
|
73 if ($req = $route->getRequirement('_method')) { |
|
74 $methods = explode('|', strtoupper($req)); |
|
75 // GET and HEAD are equivalent |
|
76 if (in_array('GET', $methods) && !in_array('HEAD', $methods)) { |
|
77 $methods[] = 'HEAD'; |
|
78 } |
|
79 $allow = array(); |
|
80 foreach ($methods as $method) { |
|
81 $methodVars[] = $method; |
|
82 $allow[] = 'E=_ROUTING__allow_'.$method.':1'; |
|
83 } |
|
84 |
|
85 $rule[] = "RewriteCond %{REQUEST_URI} $regex"; |
|
86 $rule[] = sprintf("RewriteCond %%{REQUEST_METHOD} !^(%s)$ [NC]", implode('|', $methods)); |
|
87 $rule[] = sprintf('RewriteRule .* - [S=%d,%s]', $hasTrailingSlash ? 2 : 1, implode(',', $allow)); |
|
88 } |
|
89 |
|
90 // redirect with trailing slash appended |
|
91 if ($hasTrailingSlash) { |
|
92 $rule[] = 'RewriteCond %{REQUEST_URI} '.substr($regex, 0, -2).'$'; |
|
93 $rule[] = 'RewriteRule .* $0/ [QSA,L,R=301]'; |
|
94 } |
|
95 |
|
96 // the main rule |
|
97 $rule[] = "RewriteCond %{REQUEST_URI} $regex"; |
|
98 $rule[] = "RewriteRule .* {$options['script_name']} [QSA,L,$variables]"; |
|
99 |
|
100 $rules[] = implode("\n", $rule); |
|
101 } |
|
102 |
|
103 if (0 < count($methodVars)) { |
|
104 $rule = array('# 405 Method Not Allowed'); |
|
105 $methodVars = array_values(array_unique($methodVars)); |
|
106 foreach ($methodVars as $i => $methodVar) { |
|
107 $rule[] = sprintf('RewriteCond %%{_ROUTING__allow_%s} !-z%s', $methodVar, isset($methodVars[$i + 1]) ? ' [OR]' : ''); |
|
108 } |
|
109 $rule[] = sprintf('RewriteRule .* %s [QSA,L]', $options['script_name']); |
|
110 |
|
111 $rules[] = implode("\n", $rule); |
|
112 } |
|
113 |
|
114 return implode("\n\n", $rules)."\n"; |
|
115 } |
|
116 } |