Issues (443)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

backend/controllers/PostController.php (17 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * @link http://www.writesdown.com/
4
 * @copyright Copyright (c) 2015 WritesDown
5
 * @license http://www.writesdown.com/license/
6
 */
7
8
namespace backend\controllers;
9
10
use common\models\Option;
11
use common\models\Post;
12
use common\models\PostType;
13
use common\models\search\Post as PostSearch;
14
use common\models\Term;
15
use common\models\TermRelationship;
16
use Yii;
17
use yii\filters\AccessControl;
18
use yii\filters\VerbFilter;
19
use yii\web\Controller;
20
use yii\web\ForbiddenHttpException;
21
use yii\web\NotFoundHttpException;
22
use yii\web\Response;
23
24
/**
25
 * PostController implements the CRUD actions for Post model.
26
 *
27
 * @author Agiel K. Saputra <[email protected]>
28
 * @since 0.1.0
29
 */
30
class PostController extends Controller
31
{
32
    /**
33
     * @inheritdoc
34
     */
35
    public function behaviors()
36
    {
37
        return [
38
            'access' => [
39
                'class' => AccessControl::className(),
40
                'rules' => [
41
                    [
42
                        'actions' => ['index', 'create', 'update', 'delete', 'bulk-action', 'ajax-search'],
43
                        'allow' => true,
44
                        'roles' => ['subscriber'],
45
                    ],
46
                ],
47
            ],
48
            'verbs' => [
49
                'class' => VerbFilter::className(),
50
                'actions' => [
51
                    'delete' => ['post'],
52
                    'bulk-action' => ['post'],
53
                    'ajax-search' => ['post'],
54
                ],
55
            ],
56
        ];
57
    }
58
59
    /**
60
     * Lists all Post models on specific post type.
61
     * If there is user, the action will generate list of all Post models based on user.
62
     *
63
     * @param integer $type
64
     * @param null|string $user
65
     * @throws \yii\web\ForbiddenHttpException
66
     * @throws \yii\web\NotFoundHttpException
67
     * @return mixed
68
     */
69
    public function actionIndex($type, $user = null)
70
    {
71
        $postType = $this->findPostType($type);
72
        $searchModel = new PostSearch();
73
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams, $type, $user);
74
75
        if (!Yii::$app->user->can($postType->permission)) {
76
            throw new ForbiddenHttpException(Yii::t('writesdown', 'You are not allowed to perform this action.'));
77
        }
78
79
        return $this->render('index', [
80
            'searchModel' => $searchModel,
81
            'dataProvider' => $dataProvider,
82
            'postType' => $postType,
83
            'user' => $user,
84
        ]);
85
    }
86
87
    /**
88
     * Creates a new Post model.
89
     * If creation is successful, the browser will be redirected to the 'update' page.
90
     *
91
     * @param integer $type Post type ID
92
     * @throws \yii\web\ForbiddenHttpException
93
     * @throws \yii\web\NotFoundHttpException
94
     * @return mixed
95
     */
96
    public function actionCreate($type)
97
    {
98
        $model = new Post();
99
        $postType = $this->findPostType($type);
100
        $model->comment_status = Option::get('default_comment_status');
101
102
        if (!Yii::$app->user->can($postType->permission)) {
103
            throw new ForbiddenHttpException(Yii::t('writesdown', 'You are not allowed to perform this action.'));
104
        }
105
106
        if ($model->load(Yii::$app->request->post())) {
107
            $model->type = $postType->id;
108
            $model->date = date('Y-m-d H:i:s', strtotime($model->date));
109
            if ($model->save()) {
110
                if ($termIds = Yii::$app->request->post('termIds')) {
111
                    foreach ($termIds as $termId) {
112
                        $termRelationship = new TermRelationship();
113
                        $termRelationship->setAttributes([
114
                            'term_id' => $termId,
115
                            'post_id' => $model->id,
116
                        ]);
117
                        if ($termRelationship->save() && $term = $this->findTerm($termId)) {
118
                            $term->updateAttributes(['count' => ++$term->count]);
0 ignored issues
show
The method updateAttributes cannot be called on $term (of type array|boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
119
                        }
120
                    }
121
                }
122 View Code Duplication
                if ($meta = Yii::$app->request->post('meta')) {
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.

Loading history...
123
                    foreach ($meta as $name => $value) {
124
                        $model->setMeta($name, $value);
125
                    }
126
                }
127
                Yii::$app->getSession()->setFlash('success',
0 ignored issues
show
The method getSession does only exist in yii\web\Application, but not in yii\console\Application.

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

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
128
                    Yii::t('writesdown', '{type} successfully saved.', ['type' => $postType->singular_name, ]));
129
                return $this->redirect(['update', 'id' => $model->id]);
130
            }
131
        }
132
133
        return $this->render('create', [
134
            'model' => $model,
135
            'postType' => $postType,
136
        ]);
137
    }
138
139
    /**
140
     * Updates an existing Post model.
141
     * If update is successful, the browser will be redirected to the 'view' page.
142
     *
143
     * @param integer $id
144
     * @throws \yii\web\ForbiddenHttpException
145
     * @throws \yii\web\NotFoundHttpException
146
     * @return mixed
147
     */
148
    public function actionUpdate($id)
149
    {
150
        $model = $this->findModel($id);
151
        $this->getPermission($model);
152
        $postType = $model->postType;
153
154
        if ($model->load(Yii::$app->request->post())) {
0 ignored issues
show
The method load cannot be called on $model (of type array|boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
155
            $model->date = date('Y-m-d H:i:s', strtotime($model->date));
156
            if ($model->save()) {
0 ignored issues
show
The method save cannot be called on $model (of type array|boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
157 View Code Duplication
                if ($meta = Yii::$app->request->post('meta')) {
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.

Loading history...
158
                    foreach ($meta as $name => $value) {
159
                        $model->setMeta($name, $value);
0 ignored issues
show
The method setMeta cannot be called on $model (of type array|boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
160
                    }
161
                }
162
                Yii::$app->getSession()->setFlash('success',
0 ignored issues
show
The method getSession does only exist in yii\web\Application, but not in yii\console\Application.

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

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
163
                    Yii::t('writesdown', '{type} successfully saved.', ['type' => $postType->singular_name, ]));
164
                return $this->redirect(['post/update', 'id' => $id]);
165
            }
166
        }
167
168
        return $this->render('update', [
169
            'model' => $model,
170
            'postType' => $postType,
171
        ]);
172
    }
173
174
    /**
175
     * Deletes an existing Post model.
176
     * If deletion is successful, the browser will be redirected to the 'index' page.
177
     *
178
     * @param integer $id
179
     * @throws \Exception
180
     * @throws \yii\web\ForbiddenHttpException
181
     * @throws \yii\web\NotFoundHttpException
182
     * @return mixed
183
     */
184
    public function actionDelete($id)
185
    {
186
        $model = $this->findModel($id);
187
        $this->getPermission($model);
188
        $terms = $model->terms;
189
190
        if ($model->delete()) {
0 ignored issues
show
The method delete cannot be called on $model (of type array|boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
191
            foreach ($terms as $term) {
192
                $term->updateAttributes(['count' => --$term->count]);
193
            }
194
        }
195
196
        return $this->redirect(['index', 'type' => $model->type]);
197
    }
198
199
    /**
200
     * Bulk action for Post triggered when button 'Apply' clicked.
201
     * The action depends on the value of the dropdown next to the button.
202
     * Only accept POST HTTP method.
203
     */
204
    public function actionBulkAction()
205
    {
206
        if (Yii::$app->request->post('action') === Post::STATUS_PUBLISH) {
207
            foreach (Yii::$app->request->post('ids', []) as $id) {
208
                $model = $this->findModel($id);
209
                $this->getPermission($model);
210
                $model->updateAttributes(['status' => Post::STATUS_PUBLISH]);
0 ignored issues
show
The method updateAttributes cannot be called on $model (of type array|boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
211
            }
212 View Code Duplication
        } elseif (Yii::$app->request->post('action') === Post::STATUS_DRAFT) {
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.

Loading history...
213
            foreach (Yii::$app->request->post('ids', []) as $id) {
214
                $model = $this->findModel($id);
215
                $this->getPermission($model);
216
                $model->updateAttributes(['status' => Post::STATUS_DRAFT]);
0 ignored issues
show
The method updateAttributes cannot be called on $model (of type array|boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
217
            }
218
        } elseif (Yii::$app->request->post('action') === Post::STATUS_PRIVATE) {
219
            foreach (Yii::$app->request->post('ids', []) as $id) {
220
                $model = $this->findModel($id);
221
                $this->getPermission($model);
222
                $model->updateAttributes(['status' => Post::STATUS_PRIVATE]);
0 ignored issues
show
The method updateAttributes cannot be called on $model (of type array|boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
223
            }
224 View Code Duplication
        } elseif (Yii::$app->request->post('action') === Post::STATUS_TRASH) {
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.

Loading history...
225
            foreach (Yii::$app->request->post('ids', []) as $id) {
226
                $model = $this->findModel($id);
227
                $this->getPermission($model);
228
                $model->updateAttributes(['status' => Post::STATUS_TRASH]);
0 ignored issues
show
The method updateAttributes cannot be called on $model (of type array|boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
229
            }
230
        } elseif (Yii::$app->request->post('action') === Post::STATUS_REVIEW) {
231
            foreach (Yii::$app->request->post('ids', []) as $id) {
232
                $model = $this->findModel($id);
233
                $this->getPermission($model);
234
                $model->updateAttributes(['status' => Post::STATUS_REVIEW]);
0 ignored issues
show
The method updateAttributes cannot be called on $model (of type array|boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
235
            }
236
        } elseif (Yii::$app->request->post('action') === 'delete') {
237
            foreach (Yii::$app->request->post('ids', []) as $id) {
238
                $model = $this->findModel($id);
239
                $this->getPermission($model);
240
                $terms = $model->terms;
241
                if ($model->delete()) {
0 ignored issues
show
The method delete cannot be called on $model (of type array|boolean).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
242
                    foreach ($terms as $term) {
243
                        $term->updateAttributes(['count' => --$term->count]);
244
                    }
245
                }
246
            }
247
        }
248
    }
249
250
    /**
251
     * Search POST model via AJAX with JSON as the response.
252
     */
253
    public function actionAjaxSearch()
254
    {
255
        Yii::$app->response->format = Response::FORMAT_JSON;
256
        $query = Post::find()
257
            ->select(['id', 'title'])
258
            ->andWhere(['like', 'title', Yii::$app->request->post('title')])
259
            ->limit(10);
260
261
        if ($postType = Yii::$app->request->post('type')) {
262
            $query->andWhere(['type' => $postType]);
263
        }
264
265
        return $query->all();
266
    }
267
268
    /**
269
     * Get permission to access model by current user.
270
     * If the user does not obtain the permission, a 403 exeption will be thrown.
271
     *
272
     * @param $model Post
273
     * @throws ForbiddenHttpException
274
     */
275
    public function getPermission($model)
276
    {
277
        if (!$model->getPermission()) {
278
            throw new ForbiddenHttpException(Yii::t('writesdown', 'You are not allowed to perform this action.'));
279
        }
280
    }
281
282
    /**
283
     * Finds the Post model based on its primary key value.
284
     * If the model is not found, a 404 HTTP exception will be thrown.
285
     *
286
     * @param integer $id
287
     * @return Post the loaded model
288
     * @throws NotFoundHttpException if the model cannot be found
289
     */
290
    protected function findModel($id)
291
    {
292
        if (($model = Post::findOne($id)) !== null) {
293
            return $model;
294
        }
295
296
        throw new NotFoundHttpException('The requested page does not exist.');
297
    }
298
299
    /**
300
     * Finds the PostType model based on its primary key value.
301
     * If the model is not found, a 404 HTTP exception will be thrown.
302
     *
303
     * @param integer $id
304
     * @return PostType the loaded model
305
     * @throws NotFoundHttpException if the model cannot be found
306
     */
307
    protected function findPostType($id)
308
    {
309
        if (($model = PostType::findOne($id)) !== null) {
310
            return $model;
311
        }
312
313
        throw new NotFoundHttpException('The requested page does not exist.');
314
    }
315
316
    /**
317
     * Finds the Term model based on its primary key value.
318
     * If the model is not found, it return false.
319
     *
320
     * @param integer $id
321
     * @return Term|bool|null|static
322
     */
323
    protected function findTerm($id)
324
    {
325
        if (($model = Term::findOne($id)) !== null) {
326
            return $model;
327
        }
328
329
        return false;
330
    }
331
}
332