Issues (632)

Security Analysis    not enabled

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

  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.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  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.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  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.
  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.
  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.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  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.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  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.
  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.
  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.
  Header Injection
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.

Apps/View/Front/default/profile/show.php (2 issues)

1
<?php
2
3
use Apps\ActiveRecord\ProfileField;
4
use Ffcms\Core\Helper\Date;
5
use Ffcms\Core\Helper\Type\Any;
6
use Ffcms\Core\Helper\Type\Str;
7
use Ffcms\Templex\Url\Url;
8
9
/** @var Apps\ActiveRecord\User $user Target user object */
10
/** @var Apps\ActiveRecord\User $viewer Viewer user object */
11
/** @var Apps\ActiveRecord\WallPost $wallRecords */
12
/** @var \Apps\Model\Front\Profile\FormWallPost $wall */
13
/** @var array $notify */
14
/** @var bool $isSelf */
15
/** @var bool $ratingOn */
16
/** @var array $pagination */
17
/** @var Ffcms\Templex\Template\Template $this */
18
19
// $user is a target profile depended object(not current user!!!)
20
21
$name = $user->profile === null ? __('Unknown') : $user->profile->getNickname();
22
23
$this->layout('_layouts/default', [
24
    'title' => __('Profile') . ': ' . $name,
25
    'breadcrumbs' => [
26
        Url::to('/') => __('Home'),
27
        __('Profile') . ': ' . $name
28
    ]
29
]);
30
31
?>
32
<?php $this->start('body') ?>
33
<div class="row">
34
    <div class="col-md-12">
35
        <h1><?= $name ?> <sup><small>id: <?= $user->id; ?></small></sup></h1>
36
    </div>
37
</div>
38
<hr/>
39
<?php if (\App::$User->isAuth() && $user->inBlacklist($viewer->getId())): ?>
40
    <p class="alert alert-danger"><?= __('You are in blacklist of this user. Your access is limited.') ?></p>
41
<?php endif; ?>
42
<div class="row">
43
    <div class="col-md-4">
44
        <img src="<?= $user->profile->getAvatarUrl('big') ?>" class="img-fluid img-thumbnail" />
45
        <?php if ($ratingOn):
46
            $rateClass = 'btn-secondary';
47
            $rateValue = (int)$user->profile->rating;
48
            if ($user->profile->rating > 0) {
49
                $rateClass = 'btn-info';
50
            } elseif ($user->profile->rating < 0) {
51
                $rateClass = 'btn-warning';
52
            }
53
            ?>
54
            <?php if ($isSelf): ?>
55
            <div class="row">
56
                <div class="col-md-12">
57
                    <button type="button" href="javascript:void(0);" class="btn btn-block <?= $rateClass ?>">
58
                        <?= __('Rating') ?>: <span class="badge"><?= $rateValue ?></span>
59
                    </button>
60
                </div>
61
            </div>
62
            <?php else: ?>
63
                <div class="row">
64
                    <div class="col-md-8" style="padding-right: 0;">
65
                        <a href="javascript:void(0);" class="btn btn-block <?= $rateClass ?>">
66
                            <?= __('Rating') ?>:
67
                            <span class="badge"><?= $rateValue > 0 ? '+' : null ?>
68
                                <span id="ratingValue"><?= $rateValue ?></span>
69
                        </span>
70
                        </a>
71
                    </div>
72
                    <div class="col-md-2" style="padding-left: 1px;padding-right: 0;">
73
                        <button id="addRating" class="btn btn-block btn-success">+</button>
74
                    </div>
75
                    <div class="col-md-2" style="padding-left: 1px; padding-right: 0;">
76
                        <button class="btn btn-block btn-danger" id="reduceRating">-</button>
77
                    </div>
78
                </div>
79
            <?php endif; ?>
80
        <?php endif; ?>
81
        <?php
82
        $userMenu = $this->bootstrap()->nav('ul', ['class' => 'nav-tabs flex-column']);
83
        if ($isSelf) {
84
            $userMenu->menu(['link' => ['profile/feed'], 'text' => '<i class="fa fa-rss-square"></i> ' . __('Feed'), 'html' => true]);
85
            $userMenu->menu(['link' => ['profile/avatar'], 'text' => '<i class="fa fa-camera"></i> ' . __('Avatar'), 'html' => true]);
86
            $userMenu->menu(['link' => ['profile/messages'], 'text' => '<i class="fa fa-envelope"></i> ' . __('Messages') . ' <span class="badge pm-count-block">0</span>', 'html' => true]);
87
            $userMenu->menu(['link' => ['profile/settings'], 'text' => '<i class="fa fa-cogs"></i> ' . __('Settings'), 'html' => true]);
88
        } else if(\App::$User->isAuth()) {
89
            $userMenu->menu(['link' => ['profile/messages', null, ['newdialog' => $user->id]], 'text' => __('Write message')]);
90
            $userMenu->menu(['link' => ['profile/ignore', null, ['id' => $user->id]], 'text' => __('Block')]);
91
        }
92
        echo $userMenu->display();
93
        ?>
94
    </div>
95
    <div class="col-md-8">
96
        <h2><?= __('Profile data'); ?></h2>
97
        <div class="table-responsive">
98
            <table class="table table-striped">
99
                <tr>
100
                    <td><?= __('Group') ?></td>
101
                    <td><span class="badge badge-secondary" style="background-color: <?= $user->role->color ?>;"><?= $user->role->name ?></span></td>
102
                </tr>
103
                <tr>
104
                    <td><?= __('Join date'); ?></td>
105
                    <td><?= Date::convertToDatetime($user->created_at, Date::FORMAT_TO_DAY); ?></td>
106
                </tr>
107
                <?php if ($user->profile->birthday !== null && !Str::startsWith('0000-', $user->profile->birthday)): ?>
108
                    <tr>
109
                        <td><?= __('Birthday'); ?></td>
110
                        <td>
111
                            <?= Url::a(
112
                                ['profile/index', ['born', Date::convertToDatetime($user->profile->birthday, 'Y')]],
113
                                Date::convertToDatetime($user->profile->birthday, Date::FORMAT_TO_DAY)
114
                            ) ?>
115
                        </td>
116
                    </tr>
117
                <?php endif; ?>
118
                <?php $sex = $user->profile->sex ?>
119
                <tr>
120
                    <td><?= __('Sex'); ?></td>
121
                    <td>
122
                        <?php
123
                        if ($sex == 1) { // could be string(1) "1" or int(1) 1
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
124
                            echo __('Male');
125
                        } elseif ($sex == 2) {
126
                            echo __('Female');
127
                        } else {
128
                            echo __('Unknown');
129
                        }
130
                        ?>
131
                    </td>
132
                </tr>
133
                <?php if (!Str::likeEmpty($user->profile->phone)): ?>
134
                    <tr>
135
                        <td><?= __('Phone'); ?></td>
136
                        <td><?= $user->profile->phone ?></td>
137
                    </tr>
138
                <?php endif; ?>
139
                <?php if (!Str::likeEmpty($user->profile->url)): ?>
140
                    <tr>
141
                        <td><?= __('Website'); ?></td>
142
                        <td>
143
                            <a rel="nofollow" target="_blank" href="<?= $user->profile->url ?>"><?= __('Visit'); ?></a>
144
                        </td>
145
                    </tr>
146
                <?php endif; ?>
147
                <?php if (!Str::likeEmpty($user->profile->city)):
148
                    $city = trim($user->profile->city);
149
                    ?>
150
                    <tr>
151
                        <td><?= __('City') ?></td>
152
                        <td><?= Url::a(['profile/index', ['city', $city]], $city) ?></td>
153
                    </tr>
154
                <?php endif; ?>
155
                <?php if (!Str::likeEmpty($user->profile->hobby)): ?>
156
                    <tr>
157
                        <td><?= __('Interests'); ?></td>
158
                        <td>
159
                            <?php
160
                            $hobbyArray = explode(',', $user->profile->hobby);
161
                            foreach ($hobbyArray as $item) {
162
                                $item = \App::$Security->strip_tags($item);
163
                                if (!Str::likeEmpty($item)) {
164
                                    echo Url::a(['profile/index', ['hobby', trim($item, ' ')]], $item, ['class' => 'badge badge-secondary']) . ' ';
165
                                }
166
                            }
167
                            ?>
168
                        </td>
169
                    </tr>
170
                <?php endif; ?>
171
                <?php
172
                $customFields = $user->profile->custom_data;
173
                if ($customFields !== null && Any::isArray($customFields) && count($customFields) > 0): ?>
174
                    <?php foreach ($customFields as $cid => $value): ?>
175
                        <?php if (!Str::likeEmpty($value)): ?>
176
                            <tr>
177
                                <td><?= ProfileField::getNameById($cid) ?></td>
178
                                <td>
179
                                    <?php
180
                                    if (ProfileField::getTypeById($cid) === 'link') {
181
                                        echo Url::a($value, Str::sub($value, 30));
182
                                    } else {
183
                                        echo \App::$Security->strip_tags($value);
184
                                    }
185
                                    ?>
186
                                </td>
187
                            </tr>
188
                        <?php endif; ?>
189
                    <?php endforeach; ?>
190
                <?php endif; ?>
191
            </table>
192
        </div>
193
        <h2><?= __('Wall') ?></h2>
194
        <?php if ($wall !== null): ?>
195
            <?php $form = $this->form($wall) ?>
196
            <?= $form->start() ?>
197
            <?= $form->field()->textarea('message', ['class' => 'form-control wysiwyg']) ?>
198
            <input type="submit" name="<?= $wall->getFormName() ?>[submit]" value="<?= __('Send') ?>" class="btn btn-primary" />
199
200
            <?php //Ffcms\Widgets\Ckeditor\Ckeditor::widget(['targetClass' => 'wysiwyg', 'config' => 'config-small', 'jsConfig' => ['height' => '80']]); ?>
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
201
            <?= $form->stop() ?>
202
        <?php endif; ?>
203
        <?php
204
        if ($wallRecords !== null):
205
            foreach ($wallRecords as $post):
206
                /** @var \Apps\ActiveRecord\WallPost $post */
207
                ?>
208
                <div class="row object-lightborder" id="wall-post-<?= $post->id ?>">
209
                    <div class="col-xs-4 col-md-2">
210
                        <div class="text-center">
211
                            <img class="img-fluid img-rounded" alt="Avatar of <?= $post->senderUser->profile->getNickname() ?>" src="<?= $post->senderUser->profile->getAvatarUrl('small') ?>" />
212
                        </div>
213
                    </div>
214
                    <div class="col-xs-8 col-md-10">
215
                        <div class="h5" style="margin-top: 0;margin-bottom: 5px;">
216
                            <i class="glyphicon glyphicon-user"></i>
217
                            <?= Url::a(['profile/show', [$post->sender_id]], $post->senderUser->profile->getNickname(), ['style' => 'color: ' . $post->senderUser->role->color]) ?>
218
                            <small class="float-right"><?= Date::humanize($post->updated_at); ?></small>
219
                        </div>
220
                        <div class="object-text">
221
                            <?= $post->message ?>
222
                        </div>
223
                        <hr style="margin: 5px;" />
224
                        <div><i class="fa fa-comment"></i>
225
                            <a href="#wall-post-<?= $post->id ?>" id="wall-post-response-<?= $post->id ?>" class="show-wall-response">
226
                                <?= __('Answers') ?> (<span id="wall-post-response-count-<?= $post->id ?>">0</span>)
227
                            </a>
228
                            <?php if ($post->target_id === $viewer->id || $post->sender_id === $viewer->id): ?>
229
                                <?= Url::a(['profile/walldelete', [$post->id]], __('Delete'), ['class' => 'float-right']) ?>
230
                            <?php endif; ?>
231
                        </div>
232
                        <div id="wall-answer-dom-<?= $post->id; ?>" class="d-none"></div>
233
                    </div>
234
                </div>
235
            <?php
236
            endforeach;
237
        endif;
238
        ?>
239
        <?= $this->bootstrap()->pagination(['profile/show', [$user->id]], ['class' => 'pagination justify-content-center'])
240
            ->size($pagination['total'], $pagination['page'], $pagination['step'])
241
            ->display() ?>
242
    </div>
243
</div>
244
245
<!-- add answer dom template -->
246
<div id="add-answer-field" class="d-none">
247
    <hr style="margin: 5px;"/>
248
    <input type="text" id="make-answer" placeHolder="<?= __('Write comment') ?>" class="form-control wall-answer-text" maxlength="200"/>
249
    <a style="margin-top: 5px;" href="#wall-post" class="send-wall-answer btn btn-primary btn-sm" id="send-wall">
250
        <?= __('Send') ?>
251
    </a>
252
    <span class="float-right" id="answer-counter">200</span>
253
</div>
254
<div id="show-answer-list" class="d-none">
255
    <div class="row wall-answer">
256
        <div class="col-md-2 col-xs-4"><img id="wall-answer-avatar" src="<?= \App::$Alias->scriptUrl ?>/upload/user/avatar/small/default.jpg" alt="avatar" class="img-fluid img-rounded avatar" /></div>
257
        <div class="col-md-10 col-xs-8">
258
            <div class="answer-header">
259
                <a href="<?= \App::$Alias->baseUrl ?>/profile/index" id="wall-answer-userlink">unknown</a>
260
                <small class="float-right"><span id="wall-answer-date">01.01.1970</span>
261
                    <a href="#send-wall-object" class="delete-answer d-none" id="delete-answer"><i class="glyphicon glyphicon-remove"></i></a>
262
                </small>
263
            </div>
264
            <div id="wall-answer-text"></div>
265
        </div>
266
    </div>
267
</div>
268
269
270
<script>
271
    var hideAnswers = [];
272
    $(document).ready(function () {
273
        var elements = $('.object-lightborder');
274
        var viewer_id = 0;
275
        var target_id = 0;
276
        var is_self_profile = <?= $isSelf === true ? 'true' : 'false' ?>;
277
        <?php if (\App::$User->isAuth()): ?>
278
        viewer_id = <?= $viewer->getId() ?>;
279
        <?php endif; ?>
280
        target_id = <?= $user->getId() ?>;
281
        var postIds = [];
282
        $.each(elements, function (key, val) {
283
            postIds.push(val.id.replace('wall-post-', ''));
284
        });
285
286
        // load answers count via JSON
287
        if (postIds.length > 0) {
288
            $.getJSON(script_url + '/api/profile/wallanswercount/' + postIds.join(',') + '?lang=' + script_lang, function (json) {
289
                // data is successful loaded, lets parse it and set to exist dom elements as text value
290
                if (json.status === 1) {
291
                    $.each(json.data, function (key, val) {
292
                        $('#wall-post-response-count-' + key).text(val);
293
                    });
294
                }
295
            });
296
        }
297
298
        // load answers via JSON and add to current DOM
299
        loadAnswers = function (postId) {
300
            $.getJSON(script_url + '/api/profile/showwallanswers/' + postId + '?lang=' + script_lang, function (json) {
301
                if (json.status !== 1) {
302
                    return null;
303
                }
304
305
                var answerField = $('#add-answer-field').clone();
306
                var answerDom = $('#show-answer-list').clone();
307
                answerField.removeAttr('id').removeClass('d-none');
308
                answerDom.removeAttr('id').removeClass('d-none');
309
                // add hidden div with wall post object id
310
                answerField.prepend($('<div></div>').attr('id', 'send-wall-object-' + postId));
311
                // set make answer wall post object id
312
                answerField.find('#make-answer').attr('id', 'make-answer-' + postId);
313
                // build send submit button - set id and href to wall post object anchor
314
                answerField.find('#send-wall').attr('id', 'send-wall-' + postId).attr('href', '#wall-post-' + postId);
315
                // build counter (max chars in input = 200)
316
                answerField.find('#answer-counter').attr('id', 'answer-counter-' + postId);
317
318
                var addAnswerField = '';
319
                if (viewer_id > 0) {
320
                    addAnswerField = answerField.html();
321
                }
322
323
                var answers = '';
324
                $.each(json.data, function (idx, row) {
325
                    // clone general dom element
326
                    var dom = answerDom.clone();
327
                    // set avatar src
328
                    dom.find('#wall-answer-avatar')
329
                        .attr('src', row.user_avatar)
330
                        .removeAttr('id');
331
                    // set user link
332
                    dom.find('#wall-answer-userlink')
333
                        .attr('href', '<?= Url::to('profile/show') ?>/' + row.user_id).text(row.user_nick)
334
                        .attr('style', 'color: '+row.user_color)
335
                        .removeAttr('id');
336
                    // set date
337
                    dom.find('#wall-answer-date').text(row.answer_date).removeAttr('id');
338
                    // set message text
339
                    dom.find('#wall-answer-text').text(row.answer_message);
340
                    // check if this user can remove answers - answer writer or target user profile
341
                    if (is_self_profile || row.user_id === viewer_id) {
342
                        dom.find('#delete-answer')
343
                            .attr('href', '#send-wall-object-' + postId)
344
                            .attr('id', 'delete-answer-' + row.answer_id + '-' + postId)
345
                            .removeClass('d-none');
346
                    }
347
348
                    answers += dom.html();
349
                });
350
                $('#wall-answer-dom-' + postId).html(addAnswerField + answers);
351
            })
352
        };
353
354
        addAnswer = function (postId, message) {
355
            $.post(script_url + '/api/profile/sendwallanswer/' + postId + '?lang=' + script_lang, {message: message}, function (response) {
356
                if (response.status === 1) {
357
                    loadAnswers(postId);
358
                } else {
359
                    $('#send-wall-object-' + postId).html('<p class="alert alert-warning"><?= __('Comment send was failed! Try to send it later.') ?></p>');
360
                }
361
            }, 'json');
362
        };
363
364
365
        // if clicked on "Answers" - show it and send form
366
        $('.show-wall-response').on('click', function () {
367
            var postId = this.id.replace('wall-post-response-', '');
368
            // control hide-display on clicking to "Answers" link
369
            if (hideAnswers[postId] === true) {
370
                hideAnswers[postId] = false;
371
                $('#wall-answer-dom-' + postId).addClass('d-none');
372
                return null;
373
            } else {
374
                hideAnswers[postId] = true;
375
                $('#wall-answer-dom-' + postId).removeClass('d-none');
376
            }
377
            // load data and set html
378
            loadAnswers(postId);
379
        });
380
381
        // calc entered symbols
382
        $(document).on('keyup', '.wall-answer-text', function () {
383
            var postId = this.id.replace('make-answer-', '');
384
            var msglimit = 200;
385
            var msglength = $(this).val().length;
386
387
            var limitObject = $('#answer-counter-' + postId);
388
389
            if (msglength >= msglimit) {
390
                limitObject.html('<span class="badge badge-danger">0</span>');
391
            } else {
392
                limitObject.text(msglimit - msglength);
393
            }
394
        });
395
396
        $(document).on('click', '.delete-answer', function () {
397
            var answerIdPostId = this.id.replace('delete-answer-', '').split('-');
398
            $.getJSON(script_url + '/api/profile/deleteanswerowner/' + answerIdPostId[0] + '?lang=' + script_lang, function (response) {
399
                loadAnswers(answerIdPostId[1]);
400
            });
401
        });
402
403
        // delegate live event simple for add-ed dom element
404
        $(document).on('click', '.send-wall-answer', function () {
405
            var answerToId = this.id.replace('send-wall-', '');
406
            var message = $('#make-answer-' + answerToId).val();
407
            if (message == null || message.length < 3) {
408
                alert('<?= __('Message is too short') ?>');
409
                return null;
410
            }
411
412
            addAnswer(answerToId, message);
413
        });
414
415
        // work with + and - rating clicks
416
        changeRating = function (type) {
417
            // prevent some shits
418
            if (is_self_profile || viewer_id == 0) {
419
                return false;
420
            }
421
422
            $.post(script_url + '/api/profile/changerating?lang=' + script_lang, {type: type, target: target_id}, function (resp) {
423
                if (resp.status === 1) {
424
                    var rV = parseInt($('#ratingValue').text());
425
                    if (type == '+') {
426
                        $('#ratingValue').text(rV + 1);
427
                    } else {
428
                        $('#ratingValue').text(rV - 1);
429
                    }
430
                    alert('<?= __('Rating was successful changed') ?>');
431
                } else {
432
                    alert('<?= __('Rating cannot be changed') ?>');
433
                }
434
                $('#addRating').addClass('disabled');
435
                $('#reduceRating').addClass('disabled');
436
            }, 'json');
437
        };
438
439
        $('#addRating').on('click', function () {
440
            changeRating('+');
441
        });
442
        $('#reduceRating').on('click', function () {
443
            changeRating('-');
444
        });
445
    });
446
</script>
447
<?php $this->stop() ?>