This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace VSamovarov\LaravelLocalizer; |
||
4 | |||
5 | use Illuminate\Http\Request; |
||
6 | use Illuminate\Routing\Router; |
||
7 | use Illuminate\Contracts\Translation\Translator as TranslatorContract; |
||
8 | use Illuminate\Routing\RouteCollection; |
||
9 | use VSamovarov\LaravelLocalizer\Exceptions\NestedLocalizerRouteGroup; |
||
10 | |||
11 | class RouteGroupLocalizer |
||
12 | { |
||
13 | private $localizer; |
||
14 | private $translator; |
||
15 | private $route; |
||
16 | private $request; |
||
17 | |||
18 | |||
19 | public function __construct(Localizer $localizer, TranslatorContract $translator, Router $route, Request $request) |
||
20 | { |
||
21 | $this->localizer = $localizer; |
||
22 | $this->translator = $translator; |
||
23 | $this->route = $route; |
||
24 | $this->request = $request; |
||
25 | } |
||
26 | |||
27 | /** |
||
28 | * Cоздает группу роутеров |
||
29 | * для каждого языка с соответствующими префиксами и именами |
||
30 | * Должен быть в самом верху и оборачивать все локализируемые роутеры. |
||
31 | * |
||
32 | * @param \Closure|string|array $attributes |
||
33 | * @param \Closure|string $routes |
||
34 | * @return void |
||
35 | */ |
||
36 | public function routeGroupLocalizer($attributes, $routes) |
||
37 | { |
||
38 | /** |
||
39 | * Роутеры с языком по умолчанию, должны быть в самом низу |
||
40 | * иначе не будет работать, когда локаль по умолчанию скрывается |
||
41 | * Сортируем соответствующим образом |
||
42 | */ |
||
43 | $locales = []; |
||
44 | foreach($this->localizer->getSupportedLocales() as $lang) { |
||
45 | if($lang['slug'] === $this->localizer->getSupportedLocales() ) { |
||
46 | array_push ($locales,$lang); |
||
47 | } else { |
||
48 | array_unshift($locales,$lang); |
||
49 | } |
||
50 | } |
||
51 | |||
52 | foreach ($locales as $lang) { |
||
53 | $this->route->group([ |
||
54 | 'prefix' => $lang['prefix'], |
||
55 | 'as' => $this->localizer->getNamePrefix() . "{$lang['slug']}." |
||
56 | ], function () use ($attributes, $routes) { |
||
57 | $this->route->group($attributes, $routes); |
||
58 | }); |
||
59 | } |
||
60 | |||
61 | $routes = $this->route->getRoutes(); |
||
62 | |||
63 | /** |
||
64 | * Локализующие группы, запрещено вкладывать друг в друга |
||
65 | */ |
||
66 | if ($this->checkGroupNested($routes)) { |
||
67 | throw new NestedLocalizerRouteGroup(); |
||
68 | } |
||
69 | |||
70 | if (!app('localizer')->isHideDefaultLocaleInURL()) { |
||
71 | $this->addMainRoute($routes); |
||
72 | } |
||
73 | |||
74 | $this->translateRoutes($routes); |
||
75 | } |
||
76 | |||
77 | /** |
||
78 | * Проверяем, есть ли вложения локализующих групп роутеров. |
||
79 | * Просто анализируем имя роутера. |
||
80 | * Если в нем несколько раз встречается префикс локализации, |
||
81 | * значит группа вложенная |
||
82 | * |
||
83 | * @param RouteCollection $routes |
||
84 | * @return boolean |
||
85 | */ |
||
86 | private function checkGroupNested($routes): bool |
||
87 | { |
||
88 | $locales = $this->localizer->getSlagsSupportedLocales(); |
||
89 | $matchPattern = '{' . $this->localizer->getNamePrefix() . '(' . implode('|', $locales) . ').*[.]' . $this->localizer->getNamePrefix() . '(' . implode('|', $locales) . ')[.]' . '}'; |
||
90 | foreach (array_keys($routes->getRoutesByName()) as $name) { |
||
91 | if (preg_match($matchPattern, $name)) return true; |
||
92 | } |
||
93 | return false; |
||
94 | } |
||
95 | |||
96 | /** |
||
97 | * Создаем дополнительный роутер, для главной страницы, |
||
98 | * без указания языка - site.name/ |
||
99 | * Надо для SEO и правильной обработки редиректа |
||
100 | * В миделваре примем решения, оставить дубль страницы |
||
101 | * или делать редирект на страницу с указанием локали по умолчанию - site.name/uk |
||
102 | * |
||
103 | * @param RouteCollection $routes |
||
104 | * @return void |
||
105 | */ |
||
106 | public function addMainRoute($routes): void |
||
107 | { |
||
108 | try { |
||
109 | /** |
||
110 | * Ищем в коллекции роутер с URL '/' |
||
111 | * Если не находит, конструкция выбрасывает исключение |
||
112 | * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException |
||
113 | * тогда пытаемся сделать новый роутер |
||
114 | */ |
||
115 | $routes->match($this->request->create('/', 'GET')); |
||
116 | } catch (\Exception $e) { |
||
117 | try { |
||
118 | $action = $routes->match($this->request->create('/' . $this->localizer->getDefaultLocale(), 'GET')) |
||
119 | ->getAction(); |
||
120 | $action = array_merge($action, ['namespace' => '\\', 'prefix' => '', 'as' => '']); |
||
121 | $this->route->get('/', $action); |
||
122 | } catch (\Exception $e) { |
||
123 | // |
||
124 | } |
||
125 | } |
||
126 | } |
||
127 | |||
128 | /** |
||
129 | * Локализирует роутеры |
||
130 | * |
||
131 | * Ищет роутеры с префиксом локалайзера и устанавливает новые (переведенные) урлы |
||
132 | * |
||
133 | * @param RouteCollection $routes |
||
134 | * @return void |
||
135 | */ |
||
136 | public function translateRoutes($routes): void |
||
137 | { |
||
138 | $prefix = $this->localizer->getNamePrefix(); |
||
139 | foreach ($routes as $route) { |
||
140 | $name = $route->getName(); |
||
141 | |||
142 | if (strpos($name, $prefix) !== false) { |
||
143 | // определяем локаль из имени роутера |
||
144 | $locale = substr( |
||
145 | substr($name, 0, strpos($name, '.')), |
||
146 | strlen($this->localizer->getNamePrefix()) |
||
147 | ); |
||
148 | if ($locale) { |
||
149 | $route->setUri( |
||
150 | $this->translateUri($route->uri(), $locale, $this->localizer->getTranslationFileName(), $this->translator) |
||
151 | ); |
||
152 | } |
||
153 | } |
||
154 | } |
||
155 | } |
||
156 | |||
157 | /** |
||
158 | * Локализирует УРЛы |
||
159 | * |
||
160 | * Переводится каждый сегмент отдельно. |
||
161 | * Если перевода сегмента нет, то остается прежний |
||
162 | * |
||
163 | * @param string $uri |
||
164 | * @param string $locale |
||
165 | * @param string $group |
||
166 | * @param TranslatorContract $translator |
||
167 | * @return string |
||
168 | */ |
||
169 | public function translateUri(string $uri, string $locale, string $group, TranslatorContract $translator): string |
||
170 | { |
||
171 | $parts = array_map(function ($part) use ($locale, $group, $translator) { |
||
172 | $newPart = $translator->get("{$group}.{$part}", [], $locale, false); |
||
0 ignored issues
–
show
|
|||
173 | return $newPart == "{$group}.{$part}" ? $part : $newPart; |
||
174 | }, explode('/', $uri)); |
||
175 | return implode('/', $parts); |
||
176 | } |
||
177 | } |
||
178 |
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.