Issues (5)

Security Analysis    no request data  

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.

src/Combo.php (3 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
 * Combo widget for Yii2
4
 *
5
 * @link      https://github.com/hiqdev/yii2-combo
6
 * @package   yii2-combo
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2015-2017, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hiqdev\combo;
12
13
use hiqdev\yii2\assets\select2\Select2SelectAllAsset;
14
use Yii;
15
use yii\helpers\ArrayHelper;
16
use yii\helpers\Html;
17
use yii\helpers\Json;
18
use yii\helpers\Url;
19
use yii\web\JsExpression;
20
use yii\web\View;
21
use yii\widgets\InputWidget;
22
23
/**
24
 * Widget Combo.
25
 *
26
 * @property mixed $return see [[_return]]
27
 * @property mixed $rename see [[_rename]]
28
 * @property mixed $filter see [[_filter]]
29
 * @property mixed $pluginOptions see [[_pluginOptions]]
30
 * @property mixed $primaryFilter see [[_primaryFilter]]
31
 * @property mixed hasId
32
 */
33
class Combo extends InputWidget
34
{
35
    /**
36
     * @var array the url that will be passed to [[Url::to()]] method to create the request URL
37
     */
38
    public $url;
39
40
    /**
41
     * @var string the type of the field.
42
     * Usual should be module/comboName.
43
     * For example: client/client, hosting/account, domain/domain.
44
     * In case of the combo overriding with some specific filters,
45
     * the type should represent the filter.
46
     * For example: if the hosting/service combo is extended with filter
47
     * to show only DB services, the type should be hosting/service/db or hosting/dbService.
48
     * The decision of the style depends on overall code style and readability
49
     */
50
    public $type;
51
52
    /**
53
     * @var string the name of the representative field in the model.
54
     * Used by [[getPrimaryFilter]] to create the name of the filtering field
55
     * @see getPrimaryFilter()
56
     */
57
    public $name;
58
59
    /**
60
     * @var string md5 of the configuration.
61
     * Appears only after the combo registration in [[register]]
62
     * @see register()
63
     */
64
    public $configId;
65
66
    /**
67
     * @var array the HTML options for the input element
68
     */
69
    public $inputOptions = [];
70
71
    /**
72
     * @var string the outer element selector, that holds all of related Combos
73
     */
74
    public $formElementSelector = 'form';
75
76
    /**
77
     * @var string the language. Default is application language
78
     */
79
    public $language;
80
81
    /**
82
     * @var bool allow multiple selection
83
     */
84
    public $multiple;
85
86
    /**
87
     * @var bool allow `Select All` button. Only if multiple is true
88
     */
89
    public $selectAllButton = true;
90
91
    /**
92
     * @var array
93
     */
94
    public $current;
95
96
    /**
97
     * @var mixed returning arguments
98
     * Example:
99
     *
100
     * ```
101
     *  ['id', 'password', 'another_column']
102
     * ```
103
     *
104
     * @see getReturn()
105
     * @see setReturn()
106
     */
107
    protected $_return;
108
109
    /**
110
     * @var array renamed arguments
111
     * Example:
112
     *
113
     * ```
114
     *  [
115
     *      'new_col_name' => 'old_col_name',
116
     *      'text' => 'login',
117
     *      'deep' => 'array.subarray.value' // can extract some value from an array
118
     *  ]
119
     * ```
120
     *
121
     * @see getName()
122
     * @see setName()
123
     */
124
    protected $_rename;
125
126
    /**
127
     * @var array the static filters
128
     * Example:
129
     *
130
     * ```
131
     * [
132
     *      'someStaticValue' => ['format' => 'the_value'],
133
     *      'type'            => ['format' => 'seller'],
134
     *      'is_active'       => [
135
     *          'field'  => 'server',
136
     *          'format' => new JsExpression('function (id, text, field) {
137
     *              if (field.isSet()) {
138
     *                  return 1;
139
     *              }
140
     *          }'),
141
     *      ]
142
     * ]
143
     * @see setFilter()
144
     * @see getFilter()
145
     */
146
    protected $_filter = [];
147
148
    /**
149
     * @var string the name of the primary filter. Default: [[name]]_like
150
     * @see getPrimaryFilter
151
     * @see setPrimaryFilter
152
     */
153
    protected $_primaryFilter;
154
155
    /**
156
     * @var boolean|string whether the combo has a primary key
157
     *   null (default) - decision will be taken automatically.
158
     *                    In case when [[attribute]] has the `_id` postfix, this property will be treated as `true`
159
     *            false - the combo does not have an id. Meaning the value of the attribute will be used as the ID
160
     *           string - the explicit name of the ID attribute
161
     */
162
    public $_hasId;
163
164
    /**
165
     * Options that will be passed to the plugin.
166
     *
167
     * @var array
168
     * @see getPluginOptions()
169
     */
170
    public $_pluginOptions = [];
171
172
    /** {@inheritdoc} */
173 2
    public function init()
174
    {
175 2
        parent::init();
176
177
        // Set language
178 2
        if ($this->language === null && ($language = Yii::$app->language) !== 'en-US') {
179 2
            $this->language = substr($language, 0, 2);
180 2
        }
181 2
        if (!$this->_return) {
182 2
            $this->return = ['id'];
183 2
        }
184 2
        if (!$this->rename) {
185 2
            $this->rename = ['text' => $this->name];
186 2
        }
187 2
        if (empty($this->inputOptions['id'])) {
188
            $this->inputOptions['id'] = Html::getInputId($this->model, $this->attribute);
189
        }
190 2
        if ($this->multiple) {
191
            $this->inputOptions['multiple'] = true;
192
        }
193 2
        if (!empty($this->inputOptions['readonly'])) {
194
            // According to the HTML specification, the `select` element does not support
195
            // property `readonly`. Solution: render `readonly` field as disabled and prepend hidden
196
            // input to submit the attribute value.
197
            $this->inputOptions['disabled'] = true;
198
        }
199 2
        if (empty($this->inputOptions['data-combo-field'])) {
200 2
            $this->inputOptions['data-combo-field'] = $this->name;
201 2
        }
202 2
        if (!isset($this->inputOptions['unselect'])) {
203 2
            $this->inputOptions['unselect'] = null;
204 2
        }
205 2
    }
206
207
    public function run()
208
    {
209
        $this->registerClientConfig();
210
        $this->registerClientScript();
211
        return $this->renderInput();
212
    }
213
214
    /**
215
     * Renders text input that will be used by the plugin.
216
     * Must apply [[inputOptions]] to the HTML element.
217
     *
218
     * @param string $type for compatible reasons. Should not be used
219
     * @return string
220
     */
221
    protected function renderInput($type = null)
0 ignored issues
show
The parameter $type is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
222
    {
223
        $html = [];
224
        if (!empty($this->inputOptions['readonly'])) {
225
            // As it was said in comments of `init` method, the `select` element does not support property `readonly`.
226
            // However, disabled select will not be submitted.
227
            // Solution: render hidden input to submit the attribue value.
228
            $html[] = Html::activeHiddenInput($this->model, $this->attribute, [
229
                'id' => $this->inputOptions['id'] . '-hidden',
230
            ]);
231
        }
232
        $html[] = Html::activeDropDownList($this->model, $this->attribute, $this->getCurrentOptions(), $this->inputOptions);
233
234
        return implode('', $html);
235
    }
236
237
    public function registerClientConfig()
238
    {
239
        $view = $this->view;
240
        ComboAsset::register($view);
241
242
        $pluginOptions = Json::encode($this->pluginOptions);
243
        $this->configId = md5($this->type . $pluginOptions);
244
        $view->registerJs("$.comboConfig().add('{$this->configId}', $pluginOptions);", View::POS_READY, 'combo_' . $this->configId);
245
    }
246
247
    public function registerClientScript()
248
    {
249
        $selector = $this->inputOptions['id'];
250
        $js = "if ($('#$selector').length > 0) $('#$selector').closest('{$this->formElementSelector}').combo().register('#$selector', '$this->configId');";
251
252
        $this->view->registerJs($js);
253
    }
254
255
    public function getReturn()
256
    {
257
        return $this->_return;
258
    }
259
260
    /**
261
     * @return mixed
262
     */
263
    public function getRename()
264 2
    {
265
        return $this->_rename;
266 2
    }
267
268
    /**
269
     * @return mixed
270
     */
271
    public function getFilter()
272
    {
273
        return $this->_filter;
274
    }
275
276
    /**
277
     * @param mixed $filter
278
     */
279
    public function setFilter($filter)
280
    {
281
        $this->_filter = $filter;
0 ignored issues
show
Documentation Bug introduced by
It seems like $filter of type * is incompatible with the declared type array of property $_filter.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
282
    }
283
284
    /**
285
     * @param mixed $rename
286
     */
287
    public function setRename($rename)
288 2
    {
289
        $this->_rename = $rename;
0 ignored issues
show
Documentation Bug introduced by
It seems like $rename of type * is incompatible with the declared type array of property $_rename.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
290 2
    }
291 2
292
    /**
293
     * @param mixed $return
294
     */
295
    public function setReturn($return)
296 2
    {
297
        $this->_return = $return;
298 2
    }
299 2
300
    /**
301
     * @return string
302
     * @see _primaryFilter
303
     */
304
    public function getPrimaryFilter()
305
    {
306
        return $this->_primaryFilter ?: $this->name . '_like';
307
    }
308
309
    /**
310
     * @param $primaryFilter
311
     * @see _primaryFilter
312
     */
313
    public function setPrimaryFilter($primaryFilter)
314
    {
315
        $this->_primaryFilter = $primaryFilter;
316
    }
317
318
    /**
319
     * Returns the config of the Combo, merges with the passed $config.
320
     *
321
     * @param array $options
322
     * @return array
323
     */
324
    public function getPluginOptions($options = [])
325
    {
326
        $defaultOptions = [
327
            'name' => $this->name,
328
            'type' => $this->type,
329
            'hasId' => $this->hasId,
330
            'select2Options' => [
331
                'width'       => '100%',
332
                'placeholder' => '----------',
333
                'minimumInputLength' => '0',
334
                'ajax'        => [
335
                    'url'    => Url::toRoute($this->url ?? ''),
336
                    'type'   => 'post',
337
                    'return' => $this->return,
338
                    'rename' => $this->rename,
339
                    'filter' => $this->filter,
340
                    'data' => new JsExpression("
341
                        function (event) {
342
                            return $(this).data('field').createFilter($.extend(true, {
343
                                '{$this->primaryFilter}': {format: event.term}
344
                            }, event.filters || {}));
345
                        }
346
                    "),
347
                ],
348
            ],
349
        ];
350
        if ($this->multiple && $this->selectAllButton) {
351
            Select2SelectAllAsset::register($this->view);
352
            $defaultOptions = ArrayHelper::merge($defaultOptions, [
353
                'select2Options' => [
354
                    'tags' => false,
355
                    'tokenSeparators' => [',', ', ', ' '],
356
                    'dropdownAdapter' => new JsExpression('$.fn.select2.amd.require("select2/custom/dropdown-adapter/select-all")'),
357
                ],
358
            ]);
359
        }
360
361
        return ArrayHelper::merge($defaultOptions, $this->_pluginOptions, $options);
362
    }
363
364
    public function getFormIsBulk()
365
    {
366
        return preg_match("/^\[.*\].+$/", $this->attribute);
367
    }
368
369
    /**
370
     * @param array $pluginOptions
371
     */
372
    public function setPluginOptions($pluginOptions)
373
    {
374
        $this->_pluginOptions = $pluginOptions;
375
    }
376
377
    /**
378
     * @return bool|string
379
     */
380
    public function getHasId()
381
    {
382
        return $this->_hasId === null ? (substr($this->attribute, -3) === '_id') : $this->_hasId;
383
    }
384
385
    /**
386
     * @param bool|string $hasId
387
     */
388
    public function setHasId($hasId)
389
    {
390
        $this->_hasId = $hasId;
391
    }
392
393
    /**
394
     * Method collects list of options that will be rendered inside the `select` tag.
395
     * @return array
396
     */
397
    protected function getCurrentOptions()
398
    {
399
        $value = Html::getAttributeValue($this->model, $this->attribute);
400
401
        if (!isset($value) || empty($value)) {
402
            return [];
403
        }
404
405
        if (!empty($this->current)) {
406
            return $this->current;
407
        }
408
409
        if ($this->getHasId()) {
410
            if (!is_scalar($value)) {
411
                Yii::error('When Combo has ID, property $current must be set manually, or attribute value must be a scalar. Value ' . var_export($value, true) . ' is not a scalar.', __METHOD__);
412
                return [];
413
            }
414
415
            return [$value => $value];
416
        } else {
417
            if (is_array($value)) {
418
                return array_combine(array_values($value), array_values($value));
419
            }
420
421
            return [$value => $value];
422
        }
423
    }
424
}
425