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 Sergey Glagolev <[email protected]>, Nikita Melnikov <[email protected]> |
||
4 | * @link https://github.com/shogodev/argilla/ |
||
5 | * @copyright Copyright © 2003-2014 Shogo |
||
6 | * @license http://argilla.ru/LICENSE |
||
7 | * @package backend.controllers |
||
8 | * |
||
9 | * @property BModule $module |
||
10 | * @mixin TextBlockBehavior |
||
11 | * @mixin CommonBehavior |
||
12 | */ |
||
13 | abstract class BController extends CController |
||
14 | { |
||
15 | public $enabled = true; |
||
16 | |||
17 | public $position = 0; |
||
18 | |||
19 | public $name = '[Не задано]'; |
||
20 | |||
21 | public $layout = '//layouts/column1'; |
||
22 | |||
23 | /** |
||
24 | * @var array |
||
25 | */ |
||
26 | public $breadcrumbs = array(); |
||
27 | |||
28 | public $modelClass = 'BActiveRecord'; |
||
29 | |||
30 | public $popup = false; |
||
31 | |||
32 | public $moduleMenu; |
||
33 | |||
34 | public $showInMenu = true; |
||
35 | |||
36 | 40 | public function behaviors() |
|
37 | { |
||
38 | return array( |
||
39 | 40 | 'textBlock' => array('class' => 'TextBlockBehavior'), |
|
40 | 40 | 'common' => array('class' => 'CommonBehavior'), |
|
41 | 40 | ); |
|
42 | } |
||
43 | |||
44 | public function getViewPath() |
||
45 | { |
||
46 | if( ($module = $this->getModule()) === null ) |
||
47 | $module = Yii::app(); |
||
48 | |||
49 | $mappedId = array_search(get_class($this), $module->controllerMap); |
||
50 | $id = $mappedId ? $mappedId : $this->getId(); |
||
51 | |||
52 | $submoduleViewPath = $module->getViewPath().DIRECTORY_SEPARATOR.$id; |
||
53 | |||
54 | return file_exists($submoduleViewPath) ? $submoduleViewPath : $module->getViewPath(); |
||
55 | } |
||
56 | |||
57 | public function filters() |
||
58 | { |
||
59 | return array( |
||
60 | 'postOnly + delete', |
||
61 | ); |
||
62 | } |
||
63 | |||
64 | 1 | public function beforeAction($action) |
|
65 | { |
||
66 | 1 | if( !AccessHelper::checkAccessByClasses($this->module, $this) ) |
|
67 | 1 | { |
|
68 | 1 | if( !Yii::app()->user->isGuest ) |
|
69 | 1 | throw new CHttpException(403, 'Доступ запрещен.'); |
|
70 | else |
||
71 | { |
||
72 | 1 | if( Yii::app()->request->isAjaxRequest ) |
|
73 | 1 | throw new CHttpException(401, 'Требуется авторизация'); |
|
74 | |||
75 | 1 | Yii::app()->user->setReturnUrl(Yii::app()->request->requestUri); |
|
76 | 1 | $this->redirect(Yii::app()->baseUrl . '/base'); |
|
77 | } |
||
78 | } |
||
79 | |||
80 | if( in_array($action->id, array('index')) ) |
||
81 | { |
||
82 | $url = Yii::app()->request->url; |
||
83 | Yii::app()->user->setState($this->uniqueId, $url); |
||
84 | } |
||
85 | |||
86 | if( Yii::app()->request->getQuery('popup', false) ) |
||
87 | { |
||
88 | $this->popup = true; |
||
89 | $this->layout = '//layouts/popup'; |
||
90 | } |
||
91 | |||
92 | Yii::app()->registerAjaxUpdateError(); |
||
0 ignored issues
–
show
|
|||
93 | |||
94 | return parent::beforeAction($action); |
||
95 | } |
||
96 | |||
97 | 1 | public function getBackUrl() |
|
98 | { |
||
99 | 1 | $url = Yii::app()->user->getState($this->uniqueId); |
|
100 | 1 | if( !$url ) |
|
101 | 1 | $url = Yii::app()->createUrl($this->module->id.'/'.$this->id); |
|
102 | |||
103 | 1 | return Utils::cutQueryParams($url, array('ajax')); |
|
104 | } |
||
105 | |||
106 | 6 | public function actions() |
|
107 | { |
||
108 | return array( |
||
109 | 6 | 'delete' => 'BDefaultActionDelete', |
|
110 | 6 | 'deleteRelated' => 'BRelatedActionDelete', |
|
111 | 6 | 'association' => 'BSaveAssociationAction', |
|
112 | 6 | 'switch' => 'ext.jtogglecolumn.SwitchAction', |
|
113 | 6 | 'toggle' => 'ext.jtogglecolumn.ToggleAction', |
|
114 | 6 | 'onflyedit' => 'ext.onflyedit.OnFlyEditAction', |
|
115 | 6 | 'upload' => 'upload.actions.UploadAction', |
|
116 | 6 | 'directory' => 'backend.modules.directory.actions.DirectoryAction', |
|
117 | 6 | ); |
|
118 | } |
||
119 | |||
120 | /** |
||
121 | * Делаем редирект. |
||
122 | * Если приложение запущено с тестовым конфигом, то бросаем эксепшн |
||
123 | * |
||
124 | * @param mixed $url |
||
125 | * @param bool $terminate |
||
126 | * @param integer $statusCode |
||
127 | * |
||
128 | * @throws BTestRedirectException |
||
129 | */ |
||
130 | 4 | public function redirect($url, $terminate = true, $statusCode = 302) |
|
131 | { |
||
132 | 4 | if( Yii::app()->params['mode'] === 'test' ) |
|
133 | 4 | { |
|
134 | 4 | throw new BTestRedirectException(200, 'Location: '.$url, $statusCode); |
|
135 | } |
||
136 | else |
||
137 | { |
||
138 | parent::redirect($url, $terminate, $statusCode); |
||
139 | } |
||
140 | } |
||
141 | |||
142 | /** |
||
143 | * @param string $view |
||
144 | * @param null $data |
||
145 | * @param bool $return |
||
146 | * |
||
147 | * @return string|void |
||
148 | */ |
||
149 | 1 | public function render($view, $data = null, $return = false) |
|
150 | { |
||
151 | 1 | if( Yii::app()->params['mode'] === 'test' ) |
|
152 | 1 | { |
|
153 | 1 | Yii::app()->user->setFlash('render', $data); |
|
154 | 1 | } |
|
155 | else |
||
156 | { |
||
157 | parent::render($view, $data, $return); |
||
158 | } |
||
159 | 1 | } |
|
160 | |||
161 | /** |
||
162 | * @param $id |
||
163 | * @param string $modelClass |
||
164 | * |
||
165 | * @return mixed |
||
166 | * @throws CHttpException |
||
167 | */ |
||
168 | 8 | public function loadModel($id, $modelClass = null) |
|
169 | { |
||
170 | 8 | $class = $modelClass ? $modelClass : $this->modelClass; |
|
171 | 8 | $model = $class::model()->findByPk($id); |
|
172 | |||
173 | 8 | if( $model === null ) |
|
174 | 8 | throw new CHttpException(404, 'The requested page does not exist.'); |
|
175 | |||
176 | 7 | return $model; |
|
177 | } |
||
178 | |||
179 | 1 | public function actionIndex() |
|
180 | { |
||
181 | 1 | $model = $this->createFilterModel(); |
|
182 | |||
183 | 1 | $this->render('index', array( |
|
184 | 1 | 'model' => $model, |
|
185 | 1 | 'dataProvider' => $model->search(), |
|
186 | 1 | )); |
|
187 | 1 | } |
|
188 | |||
189 | public function actionCreate() |
||
190 | { |
||
191 | $model = new $this->modelClass; |
||
192 | $model->attributes = Yii::app()->request->getQuery(get_class($model)); |
||
193 | $this->actionSave($model); |
||
194 | } |
||
195 | |||
196 | /** |
||
197 | * @param $id |
||
198 | */ |
||
199 | public function actionUpdate($id) |
||
200 | { |
||
201 | $this->actionSave($this->loadModel($id)); |
||
202 | } |
||
203 | |||
204 | public function isUpdate() |
||
205 | { |
||
206 | return $this->action->id == 'update' ? true : false; |
||
207 | } |
||
208 | |||
209 | /** |
||
210 | * Стандартный автокомплит для моделей |
||
211 | * |
||
212 | * $_GET['model'] - название модели для поиска |
||
213 | * $_GET['field'] - поле для поиска |
||
214 | * $_GET['q'] - значение |
||
215 | * |
||
216 | * @return void |
||
217 | */ |
||
218 | public function actionAutocomplete() |
||
219 | { |
||
220 | if( !Yii::app()->request->isAjaxRequest ) |
||
221 | return; |
||
222 | |||
223 | $modelClass = Yii::app()->request->getParam('model'); |
||
224 | $field = Yii::app()->request->getParam('field'); |
||
225 | $value = Yii::app()->request->getParam('q'); |
||
226 | |||
227 | if( $modelClass && $field && $value ) |
||
228 | { |
||
229 | $criteria = new CDbCriteria(); |
||
230 | $criteria->addSearchCondition($field, $value); |
||
231 | $criteria->limit = 10; |
||
232 | |||
233 | $data = $modelClass::model()->findAll($criteria); |
||
234 | $answer = array(); |
||
235 | |||
236 | foreach( $data as $item ) |
||
237 | if( !in_array($item->$field, $answer) ) |
||
238 | $answer[] = $item->$field; |
||
239 | |||
240 | echo implode("\n", $answer); |
||
241 | } |
||
242 | } |
||
243 | |||
244 | /** |
||
245 | * @return BActiveRecord |
||
246 | */ |
||
247 | 1 | protected function createFilterModel() |
|
248 | { |
||
249 | 1 | $attributes = Yii::app()->request->getQuery($this->modelClass); |
|
250 | 1 | $model = new $this->modelClass('search'); |
|
251 | 1 | $model->unsetAttributes(); |
|
252 | |||
253 | 1 | if( !empty($attributes) ) |
|
254 | 1 | $model->attributes = $attributes; |
|
255 | |||
256 | 1 | return $model; |
|
257 | } |
||
258 | |||
259 | /** |
||
260 | * @param BActiveRecord $model |
||
261 | */ |
||
262 | 1 | protected function saveModel($model) |
|
263 | { |
||
264 | 1 | $this->performAjaxValidation($model); |
|
265 | 1 | $attributes = Yii::app()->request->getPost(get_class($model)); |
|
266 | |||
267 | 1 | if( isset($attributes) ) |
|
268 | 1 | { |
|
269 | 1 | $model->setAttributes($attributes); |
|
270 | |||
271 | 1 | if( $model->save() ) |
|
272 | 1 | { |
|
273 | 1 | $this->redirectAfterSave($model); |
|
274 | } |
||
275 | } |
||
276 | } |
||
277 | |||
278 | /** |
||
279 | * Проводим валидацию и сохраняем несколько связанных моделей |
||
280 | * Все модели должны быть связаны по первичному ключу |
||
281 | * |
||
282 | * @param BActiveRecord[] $models |
||
283 | * @param bool $extendedSave пытаемся сохранить все данные post, вызывая соответствующие методы контроллера |
||
284 | * @param bool $redirectToUpdate перенаправление на action update |
||
285 | * |
||
286 | * @throws CDbException |
||
287 | * @throws CHttpException |
||
288 | */ |
||
289 | 1 | protected function saveModels($models, $extendedSave = true, $redirectToUpdate = true) |
|
290 | { |
||
291 | 1 | $this->performAjaxValidationForSeveralModels($models); |
|
292 | |||
293 | 1 | if( Yii::app()->request->isPostRequest && $this->validateModels($models) ) |
|
294 | 1 | { |
|
295 | 1 | Yii::app()->db->beginTransaction(); |
|
296 | |||
297 | $modelNames = array_map(function($data){return get_class($data);}, $models); |
||
298 | 1 | $unsavedKeys = array_diff(array_keys($_POST), $modelNames); |
|
299 | 1 | $primaryModel = $models[0]; |
|
300 | |||
301 | 1 | foreach($models as $key => $model) |
|
302 | { |
||
303 | 1 | if( $key !== 0 ) |
|
304 | 1 | $model->setPrimaryKey($primaryModel->getPrimaryKey()); |
|
305 | |||
306 | 1 | View Code Duplication | if( !$model->save(false) ) |
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
307 | 1 | { |
|
308 | Yii::app()->db->currentTransaction->rollback(); |
||
309 | throw new CHttpException(500, 'Can`t save '.get_class($model).' model'); |
||
310 | } |
||
311 | 1 | } |
|
312 | |||
313 | if( $extendedSave ) |
||
314 | 1 | { |
|
315 | 1 | $resultSaveMaximumPostData = $this->saveMaximumPostData($unsavedKeys, $primaryModel); |
|
316 | |||
317 | 1 | if( !$resultSaveMaximumPostData ) |
|
318 | 1 | { |
|
319 | Yii::app()->db->currentTransaction->rollback(); |
||
320 | return; |
||
321 | } |
||
322 | 1 | } |
|
323 | |||
324 | 1 | Yii::app()->db->currentTransaction->commit(); |
|
325 | |||
326 | if( $redirectToUpdate ) |
||
327 | 1 | $this->redirectAfterSave($primaryModel); |
|
328 | } |
||
329 | } |
||
330 | |||
331 | /** |
||
332 | * @param BActiveRecord[] $models |
||
333 | * |
||
334 | * @return bool |
||
335 | */ |
||
336 | 2 | protected function validateModels($models) |
|
337 | { |
||
338 | 2 | $valid = !empty($models); |
|
339 | |||
340 | 2 | foreach($models as $model) |
|
341 | { |
||
342 | 2 | $post = Yii::app()->request->getPost(get_class($model)); |
|
343 | 2 | $model->setAttributes($post); |
|
344 | 2 | $valid = $model->validate() && $valid && !empty($post) && $this->validateRelatedModels($model); |
|
345 | 2 | } |
|
346 | |||
347 | 2 | return $valid; |
|
348 | } |
||
349 | |||
350 | /** |
||
351 | * @param BActiveRecord $model |
||
352 | * |
||
353 | * @return bool |
||
354 | */ |
||
355 | 2 | protected function validateRelatedModels($model) |
|
356 | { |
||
357 | 2 | $success = true; |
|
358 | |||
359 | 2 | foreach($this->getModelsAllowedForSave() as $relationName => $modelName) |
|
360 | { |
||
361 | if( !($postData = Yii::app()->request->getPost($modelName, null)) ) |
||
362 | continue; |
||
363 | |||
364 | $models = $model->prepareModels($relationName, $postData); |
||
365 | $success = $model->validateRelatedModels($models); |
||
366 | |||
367 | if( !$success ) |
||
368 | break; |
||
369 | 2 | } |
|
370 | |||
371 | 2 | return $success; |
|
372 | } |
||
373 | |||
374 | /** |
||
375 | * @param BActiveRecord $model |
||
376 | */ |
||
377 | 2 | protected function redirectAfterSave($model) |
|
378 | { |
||
379 | 2 | Yii::app()->user->setFlash('success', 'Запись успешно '.($model->isNewRecord ? 'создана' : 'сохранена').'.'); |
|
380 | |||
381 | 2 | if( Yii::app()->request->getParam('action') ) |
|
382 | 2 | $this->redirect($this->getBackUrl()); |
|
383 | else |
||
384 | { |
||
385 | 2 | $redirectData = CMap::mergeArray(array('id' => $model->getPrimaryKey()), $_GET); |
|
386 | 2 | $redirectUrl = $this->createUrl($this->id.'/update', $redirectData); |
|
387 | |||
388 | 2 | $this->redirect($redirectUrl); |
|
389 | } |
||
390 | } |
||
391 | |||
392 | /** |
||
393 | * @param BActiveRecord $model |
||
394 | */ |
||
395 | protected function actionSave($model) |
||
396 | { |
||
397 | $this->saveModels(array($model)); |
||
398 | $this->render('_form', array('model' => $model)); |
||
399 | } |
||
400 | |||
401 | /** |
||
402 | * Performs the AJAX validation. |
||
403 | * |
||
404 | * @param BActiveRecord $model the model to be validated |
||
405 | */ |
||
406 | 3 | protected function performAjaxValidation($model) |
|
407 | { |
||
408 | 3 | if( Yii::app()->request->getPost('ajax') === $model->getFormId() ) |
|
409 | 3 | { |
|
410 | 2 | echo CActiveForm::validate($model); |
|
411 | 2 | Yii::app()->end(); |
|
0 ignored issues
–
show
The method
end does only exist in BTestApplication and FTestApplication , but not in BApplication and FApplication .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
412 | } |
||
413 | 1 | } |
|
414 | |||
415 | /** |
||
416 | * @param BActiveRecord[] $models |
||
417 | */ |
||
418 | 3 | protected function performAjaxValidationForSeveralModels($models) |
|
419 | { |
||
420 | 3 | if( Yii::app()->request->getPost('ajax') === $models[0]->getFormId() ) |
|
421 | 3 | { |
|
422 | 2 | $result = array(); |
|
423 | |||
424 | 2 | foreach($models as $model) |
|
425 | { |
||
426 | 2 | $errors = CJavaScript::jsonDecode(CActiveForm::validate($model)); |
|
427 | 2 | $result = CMap::mergeArray($result, $errors); |
|
428 | 2 | } |
|
429 | |||
430 | 2 | echo CJavaScript::jsonEncode($result); |
|
431 | 2 | Yii::app()->end(); |
|
0 ignored issues
–
show
The method
end does only exist in BTestApplication and FTestApplication , but not in BApplication and FApplication .
It seems like the method you are trying to call exists only in some of the possible types. Let’s take a look at an example: class A
{
public function foo() { }
}
class B extends A
{
public function bar() { }
}
/**
* @param A|B $x
*/
function someFunction($x)
{
$x->foo(); // This call is fine as the method exists in A and B.
$x->bar(); // This method only exists in B and might cause an error.
}
Available Fixes
![]() |
|||
432 | } |
||
433 | 1 | } |
|
434 | |||
435 | /** |
||
436 | * Проверям наличие в контроллере методов, чтобы сохранить данные из post |
||
437 | * |
||
438 | * @param array $unsavedKeys |
||
439 | * @param BActiveRecord $primaryModel |
||
440 | * |
||
441 | * @return bool |
||
442 | */ |
||
443 | 1 | protected function saveMaximumPostData(array $unsavedKeys, BActiveRecord $primaryModel) |
|
444 | { |
||
445 | 1 | foreach($unsavedKeys as $key) |
|
446 | { |
||
447 | $method = 'save'.$key; |
||
448 | $data = Yii::app()->request->getPost($key); |
||
449 | |||
450 | if( empty($data) || !is_array($data) || !in_array($key, $this->getModelsAllowedForSave()) ) |
||
451 | continue; |
||
452 | |||
453 | if( method_exists($this, $method) ) |
||
454 | $result = call_user_func_array(array($this, $method), array($data, $primaryModel)); |
||
455 | else |
||
456 | $result = $primaryModel->saveRelatedModels(array_search($key, $this->getModelsAllowedForSave()), $data); |
||
457 | |||
458 | if( !$result ) |
||
459 | return false; |
||
460 | 1 | } |
|
461 | |||
462 | 1 | return true; |
|
463 | } |
||
464 | |||
465 | /** |
||
466 | * Возвращает массив разрешенных для сохнанеия релейшенов в формате 'relationName' => 'postPrefix' |
||
467 | * пример: array('variants' => 'BProductParamVariant'). |
||
468 | * Если в котроллере есть метод с именем save{postPrefix}($data, BActiveRecord $parentModel), |
||
469 | * то для сохнания данных $_POST[{postPrefix}} будет вызван он. |
||
470 | * |
||
471 | * @return array |
||
472 | */ |
||
473 | 2 | protected function getModelsAllowedForSave() |
|
474 | { |
||
475 | 2 | return array(); |
|
476 | } |
||
477 | } |
It seems like the method you are trying to call exists only in some of the possible types.
Let’s take a look at an example:
Available Fixes
Add an additional type-check:
Only allow a single type to be passed if the variable comes from a parameter: