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 | * @author Alexey Tatarinov <[email protected]> |
||
4 | * @link https://github.com/shogodev/argilla/ |
||
5 | * @copyright Copyright © 2003-2014 Shogo |
||
6 | * @license http://argilla.ru/LICENSE |
||
7 | * @package frontend.components |
||
8 | * |
||
9 | * @property string $header |
||
10 | * @property string $title |
||
11 | * @property string $description |
||
12 | * @property string $keywords |
||
13 | * @property string $custom |
||
14 | */ |
||
15 | class Meta extends CApplicationComponent |
||
16 | { |
||
17 | const VARIABLE_PATTERN = "/{([\w:]+)}/"; |
||
18 | |||
19 | const COMMAND_PATTERN = "/([a-z]+)\(([^()]+)\)/"; |
||
20 | |||
21 | /** |
||
22 | * @var array |
||
23 | */ |
||
24 | public $exceptedModels = array('ProductAssignment', 'ProductParameterAssignment', 'ProductTreeAssignment'); |
||
25 | |||
26 | /** |
||
27 | * @var array |
||
28 | */ |
||
29 | public $replaces = array(); |
||
30 | |||
31 | /** |
||
32 | * @var int |
||
33 | */ |
||
34 | public $maxSearchDepth = 1; |
||
35 | |||
36 | /** |
||
37 | * @var FController |
||
38 | */ |
||
39 | private $controller; |
||
40 | |||
41 | /** |
||
42 | * @var string |
||
43 | */ |
||
44 | private $route; |
||
45 | |||
46 | /** |
||
47 | * @var string |
||
48 | */ |
||
49 | private $requestUri; |
||
50 | |||
51 | /** |
||
52 | * @var FActiveRecord[] |
||
53 | */ |
||
54 | private $renderedModels = array(); |
||
55 | |||
56 | /** |
||
57 | * @var array |
||
58 | */ |
||
59 | private $renderedClips = array(); |
||
60 | |||
61 | private $header; |
||
62 | |||
63 | private $title; |
||
64 | |||
65 | private $description; |
||
66 | |||
67 | private $keywords; |
||
68 | |||
69 | private $custom; |
||
70 | |||
71 | private $noindex; |
||
72 | |||
73 | 2 | public function init() |
|
74 | { |
||
75 | 2 | parent::init(); |
|
76 | |||
77 | 2 | if( $controller = Yii::app()->controller ) |
|
78 | 2 | { |
|
79 | 2 | $this->setController($controller); |
|
80 | 2 | $this->controller->attachEventHandler('onBeforeRender', array($this, 'setRenderedModels')); |
|
81 | 2 | $this->controller->attachEventHandler('onBeforeRenderLayout', array($this, 'registerMeta')); |
|
82 | 2 | } |
|
83 | |||
84 | 2 | Yii::app()->attachEventHandler('onEndRequest', array($this, 'updateRenderedModels')); |
|
85 | |||
86 | 2 | if( isset(Yii::app()->request) ) |
|
87 | 2 | $this->setRequestUri(Yii::app()->request->requestUri); |
|
88 | |||
89 | 2 | $this->replaces = array( |
|
90 | 2 | '{project}' => Arr::get(Yii::app()->params, 'project'), |
|
91 | ); |
||
92 | 2 | } |
|
93 | |||
94 | /** |
||
95 | * @return string |
||
96 | */ |
||
97 | 18 | public function getTitle() |
|
98 | { |
||
99 | 18 | return CHtml::encode($this->clear($this->title)); |
|
100 | } |
||
101 | |||
102 | /** |
||
103 | * @return string |
||
104 | */ |
||
105 | 3 | public function getDescription() |
|
106 | { |
||
107 | 3 | return $this->clear($this->description); |
|
108 | } |
||
109 | |||
110 | /** |
||
111 | * @return string |
||
112 | */ |
||
113 | 3 | public function getKeywords() |
|
114 | { |
||
115 | 3 | return $this->clear($this->keywords); |
|
116 | } |
||
117 | |||
118 | /** |
||
119 | * @return string |
||
120 | */ |
||
121 | 7 | public function getCustom() |
|
122 | { |
||
123 | 7 | return $this->clear($this->custom); |
|
124 | } |
||
125 | |||
126 | /** |
||
127 | * @param $header |
||
128 | * |
||
129 | * @return string |
||
130 | */ |
||
131 | 6 | public function setHeader($header) |
|
132 | { |
||
133 | 6 | if( !empty($this->header) ) |
|
134 | 6 | { |
|
135 | $header = $this->clear($this->header); |
||
136 | } |
||
137 | |||
138 | 6 | $this->registerClip('h1', $header); |
|
139 | 6 | return $header; |
|
140 | } |
||
141 | |||
142 | /** |
||
143 | * @param FController $controller |
||
144 | */ |
||
145 | 7 | public function setController(FController $controller) |
|
146 | { |
||
147 | 7 | if( !isset($this->controller) ) |
|
148 | 7 | { |
|
149 | 7 | $this->controller = $controller; |
|
150 | 7 | $this->setRoute(); |
|
151 | 7 | } |
|
152 | 7 | } |
|
153 | |||
154 | /** |
||
155 | * @param string $uri |
||
156 | */ |
||
157 | 10 | public function setRequestUri($uri) |
|
158 | { |
||
159 | 10 | $this->requestUri = preg_replace('/\?.*/', '', $uri); |
|
160 | 10 | } |
|
161 | |||
162 | 14 | public function setMeta() |
|
163 | { |
||
164 | /** |
||
165 | * @var MetaMask $metaMask |
||
166 | * @var MetaRoute $metaRoute |
||
167 | */ |
||
168 | 14 | $metaMask = MetaMask::model()->findByUri($this->requestUri); |
|
169 | 14 | $metaRoute = MetaRoute::model()->findByRoute($this->route); |
|
170 | |||
171 | 14 | foreach(array('header', 'title', 'keywords', 'description', 'noindex', 'custom') as $property) |
|
172 | { |
||
173 | if( $metaRoute ) |
||
174 | 14 | $this->$property = Arr::get($metaRoute, $property); |
|
175 | |||
176 | 14 | if( $metaMask && trim($metaMask->$property) !== '' ) |
|
177 | 14 | $this->$property = $metaMask->$property; |
|
178 | 14 | } |
|
179 | |||
180 | 14 | if( empty($this->title) ) |
|
181 | 14 | { |
|
182 | $this->title = $this->controller->getPageTitle(); |
||
183 | } |
||
184 | 14 | } |
|
185 | |||
186 | /** |
||
187 | * Собираем все модели, переданные в render() |
||
188 | * |
||
189 | * @param CEvent $event |
||
190 | */ |
||
191 | 2 | public function setRenderedModels(CEvent $event) |
|
192 | { |
||
193 | 2 | $this->setRoute(); |
|
194 | 2 | $this->setMeta(); |
|
195 | |||
196 | 2 | $this->processModels(Arr::get($event->params, 'data', array())); |
|
197 | 2 | } |
|
198 | |||
199 | /** |
||
200 | * @param FActiveRecord[] $models |
||
201 | */ |
||
202 | 3 | public function addModels(array $models) |
|
203 | { |
||
204 | 3 | $this->processModels($models); |
|
205 | 3 | } |
|
206 | |||
207 | 10 | public function registerClip($id, $value) |
|
208 | { |
||
209 | 10 | $this->replaces['{'.$id.'}'] = $value; |
|
210 | 10 | $this->renderedClips[$id] = $id; |
|
211 | |||
212 | 10 | return $value; |
|
213 | } |
||
214 | |||
215 | /** |
||
216 | * Запись в базу моделей, найденных во время рендеринга |
||
217 | */ |
||
218 | 1 | public function updateRenderedModels() |
|
219 | { |
||
220 | 1 | if( strpos($this->route, '/') !== false ) |
|
221 | 1 | { |
|
222 | 1 | if( !$model = MetaRoute::model()->resetScope()->findByRoute($this->route, false) ) |
|
223 | 1 | $model = new MetaRoute(); |
|
224 | |||
225 | 1 | $model->route = $this->route; |
|
226 | 1 | $model->models = implode(',', array_keys($this->renderedModels)); |
|
227 | 1 | $model->clips = implode(',', array_keys($this->renderedClips)); |
|
228 | 1 | $model->save(); |
|
229 | 1 | } |
|
230 | 1 | } |
|
231 | |||
232 | 2 | public function registerMeta() |
|
233 | { |
||
234 | 2 | if( $clientScript = Yii::app()->clientScript ) |
|
235 | 2 | { |
|
236 | 2 | $clientScript->registerMetaTag($this->getDescription(), 'description', null, array(), 'description'); |
|
237 | 2 | $clientScript->registerMetaTag($this->getKeywords(), 'keywords', null, array(), 'keywords'); |
|
238 | |||
239 | 2 | if( $this->noindex ) |
|
240 | 2 | { |
|
241 | 1 | $clientScript->registerMetaTag('noindex, nofollow', 'robots', null, array(), 'robots'); |
|
242 | 1 | } |
|
243 | 2 | } |
|
244 | 2 | } |
|
245 | |||
246 | 7 | private function setRoute() |
|
247 | { |
||
248 | 7 | if( isset($this->controller) ) |
|
249 | 7 | $this->route = $this->controller->route; |
|
250 | 7 | } |
|
251 | |||
252 | /** |
||
253 | * Удаление переменных моделей в строке метатегов |
||
254 | * |
||
255 | * @param string $string |
||
256 | * |
||
257 | * @return string |
||
258 | */ |
||
259 | 19 | private function clear($string) |
|
260 | { |
||
261 | 19 | $string = $this->replaceVariables($string); |
|
262 | 19 | $string = $this->replaceCommands($string); |
|
263 | 19 | $string = preg_replace(self::VARIABLE_PATTERN, '', $string); |
|
264 | 19 | $string = preg_replace('/\s+/', ' ', $string); |
|
265 | |||
266 | 19 | return trim($string); |
|
267 | } |
||
268 | |||
269 | /** |
||
270 | * @param FActiveRecord[] $data |
||
271 | */ |
||
272 | 5 | private function processModels(array $data) |
|
273 | { |
||
274 | 5 | static $depth; |
|
275 | |||
276 | 5 | foreach($data as $model) |
|
277 | { |
||
278 | 4 | if( $model instanceof FActiveRecord ) |
|
279 | 4 | $modelName = get_class($model); |
|
280 | 2 | else if( $model instanceof FForm ) |
|
281 | 2 | { |
|
282 | 1 | $model = $model->model; |
|
283 | 1 | $modelName = get_class($model); |
|
284 | 1 | } |
|
285 | else |
||
286 | continue; |
||
287 | |||
288 | 4 | if( in_array($modelName, $this->exceptedModels) ) |
|
289 | 4 | continue; |
|
290 | |||
291 | 4 | $this->renderedModels[$modelName] = $model; |
|
292 | |||
293 | 4 | if( $model instanceof FActiveRecord && $depth <= $this->maxSearchDepth ) |
|
294 | 4 | { |
|
295 | 2 | $depth++; |
|
296 | 2 | $this->processRelations($model); |
|
297 | 2 | } |
|
298 | 5 | } |
|
299 | 5 | } |
|
300 | |||
301 | /** |
||
302 | * @param FActiveRecord $model |
||
303 | */ |
||
304 | 2 | private function processRelations(FActiveRecord $model) |
|
305 | { |
||
306 | 2 | foreach($model->relations() as $name => $relation) |
|
307 | { |
||
308 | if( in_array($relation[0], array(FActiveRecord::HAS_ONE, FActiveRecord::BELONGS_TO)) ) |
||
309 | { |
||
310 | if( !isset($this->renderedModels[$relation[1]]) ) |
||
311 | { |
||
312 | $this->processModels(array($model->{$name})); |
||
313 | } |
||
314 | } |
||
315 | 2 | } |
|
316 | 2 | } |
|
317 | |||
318 | /** |
||
319 | * Замена встречающиеся переменных на значения свойств $model |
||
320 | * |
||
321 | * @param $string |
||
322 | * |
||
323 | * @return string |
||
324 | */ |
||
325 | 19 | private function replaceVariables($string) |
|
326 | { |
||
327 | 19 | if( preg_match_all(self::VARIABLE_PATTERN, $string, $matches) ) |
|
328 | 19 | { |
|
329 | 17 | if( !empty($matches[0]) ) |
|
330 | 17 | { |
|
331 | 17 | foreach($matches[0] as $key => $value) |
|
332 | { |
||
333 | 17 | $replace = $matches[0][$key]; |
|
334 | 17 | $value = $matches[1][$key]; |
|
335 | 17 | $this->processValue($value, $replace); |
|
336 | 17 | } |
|
337 | 17 | } |
|
338 | |||
339 | 17 | $string = strtr($string, $this->replaces); |
|
340 | 17 | } |
|
341 | |||
342 | 19 | return $string; |
|
343 | } |
||
344 | |||
345 | 19 | private function replaceCommands($string) |
|
346 | { |
||
347 | 19 | if( preg_match(self::COMMAND_PATTERN, $string, $matches) ) |
|
348 | 19 | { |
|
349 | 5 | if( !empty($matches[0]) ) |
|
350 | 5 | { |
|
351 | 5 | $command = $matches[1]; |
|
352 | 5 | $args = $matches[2]; |
|
353 | 5 | $value = $this->processCommand($command, $args); |
|
354 | |||
355 | 5 | $string = strtr($string, array($matches[0] => $value)); |
|
356 | 5 | $string = $this->replaceCommands($string); |
|
357 | 5 | } |
|
358 | 5 | } |
|
359 | |||
360 | 19 | return $string; |
|
361 | } |
||
362 | |||
363 | /** |
||
364 | * @param $value |
||
365 | * @param $replace |
||
366 | */ |
||
367 | 17 | private function processValue($value, $replace) |
|
368 | { |
||
369 | 17 | if( strpos($value, ':') !== false ) |
|
370 | 17 | { |
|
371 | 2 | list($modelName, $attribute) = explode(':', $value); |
|
372 | 2 | $model = Arr::get($this->renderedModels, $modelName); |
|
373 | |||
374 | 2 | if( $model && ($property = $this->getPropertyValue($model, $attribute)) ) |
|
375 | 2 | { |
|
376 | 2 | $this->replaces[$replace] = $property; |
|
377 | 2 | } |
|
378 | 2 | } |
|
379 | 17 | } |
|
380 | |||
381 | /** |
||
382 | * @param string $command |
||
383 | * @param string $args |
||
384 | * |
||
385 | * @return string |
||
386 | */ |
||
387 | 5 | private function processCommand($command, $args) |
|
388 | { |
||
389 | 5 | $args = Arr::trim(explode(',', $args)); |
|
390 | |||
391 | switch($command) |
||
392 | { |
||
393 | 5 | case 'ucfirst': |
|
394 | 1 | return Utils::ucfirst($args[0]); |
|
395 | break; |
||
0 ignored issues
–
show
|
|||
396 | |||
397 | 5 | case 'upper': |
|
398 | 1 | return mb_strtoupper($args[0]); |
|
399 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
400 | |||
401 | 5 | case 'lower': |
|
402 | 1 | return mb_strtolower($args[0]); |
|
403 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
404 | |||
405 | 4 | case 'wrap': |
|
406 | 3 | $left = Arr::get($args, 1, '('); |
|
407 | 3 | $right = Arr::get($args, 2, ')'); |
|
408 | 3 | return $left.$args[0].$right; |
|
409 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
410 | |||
411 | 2 | case 'implode': |
|
412 | 1 | return implode(trim(Arr::cut($args, 0), '\'"'), $args); |
|
413 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
414 | |||
415 | 1 | default: |
|
416 | 1 | return $args[0]; |
|
417 | 1 | } |
|
418 | } |
||
419 | |||
420 | /** |
||
421 | * @param FActiveRecord $model |
||
422 | * @param string $property |
||
423 | * |
||
424 | * @return string |
||
425 | */ |
||
426 | 2 | private function getPropertyValue($model, $property) |
|
427 | { |
||
428 | 2 | return isset($model->$property) && !is_object($model->$property) && !is_array($model->$property) ? $model->$property : null; |
|
429 | } |
||
430 | } |
The break statement is not necessary if it is preceded for example by a return statement:
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.