Issues (187)

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.

traits/EntityTrait.php (10 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
/**
4
 *  _   __ __ _____ _____ ___  ____  _____
5
 * | | / // // ___//_  _//   ||  __||_   _|
6
 * | |/ // /(__  )  / / / /| || |     | |
7
 * |___//_//____/  /_/ /_/ |_||_|     |_|
8
 * @link http://vistart.name/
9
 * @copyright Copyright (c) 2016 vistart
10
 * @license http://vistart.name/license/
11
 */
12
13
namespace vistart\Models\traits;
14
15
use Yii;
16
use yii\base\ModelEvent;
17
use yii\caching\Cache;
18
use yii\caching\TagDependency;
19
20
/**
21
 * This trait must be used in class extended from ActiveRecord. The ActiveRecord
22
 * supports \yii\db\ActiveRecord, \yii\mongodb\ActiveRecord, \yii\redis\ActiveRecord.
23
 * @property array $entityRules
24
 * @property array $entityBehaviors
25
 * @version 2.0
26
 * @author vistart <[email protected]>
27
 */
28
trait EntityTrait
29
{
30
    use GUIDTrait,
31
        IDTrait,
32
        IPTrait,
33
        TimestampTrait;
34
35
    private $entityLocalRules = [];
36
    private $entityLocalBehaviors = [];
37
38
    /**
39
     * @var string cache key and tag prefix. the prefix is usually set to full
40
     * qualified class name.
41
     */
42
    public $cachePrefix = '';
43
    public static $eventNewRecordCreated = 'newRecordCreated';
44
    public static $cacheKeyEntityRules = 'entity_rules';
45
    public static $cacheTagEntityRules = 'tag_entity_rules';
46
    public static $cacheKeyEntityBehaviors = 'entity_behaviors';
47
    public static $cacheTagEntityBehaviors = 'tag_entity_behaviors';
48
49
    /**
50
     * @var string cache component id. 
51
     */
52
    public $cacheId = 'cache';
53
54
    /**
55
     * @var boolean Determines to skip initialization.
56
     */
57
    public $skipInit = false;
58
59
    /**
60
     * @var string the name of query class or sub-class.
61
     */
62
    public $queryClass;
63
64
    /**
65
     * @return \static New self without any initializations.
66
     */
67 62
    public static function buildNoInitModel()
68
    {
69 62
        return new static(['skipInit' => true]);
0 ignored issues
show
The call to EntityTrait::__construct() has too many arguments starting with array('skipInit' => true).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
70
    }
71
72
    /**
73
     * Populate and return the entity rules.
74
     * You should call this function in your extended class and merge the result
75
     * with your rules, instead of overriding it, unless you know the
76
     * consequences.
77
     * The classical rules is like following:
78
     * [
79
     *     ['guid', 'required'],
80
     *     ['guid', 'unique'],
81
     *     ['guid', 'string', 'max' => 36],
82
     * 
83
     *     ['id', 'required'],
84
     *     ['id', 'unique'],
85
     *     ['id', 'string', 'max' => 4],
86
     * 
87
     *     ['create_time', 'safe'],
88
     *     ['update_time', 'safe'],
89
     * 
90
     *     ['ip_type', 'in', 'range' => [4, 6]],
91
     *     ['ip_1', 'number', 'integerOnly' => true, 'min' => 0],
92
     *     ['ip_2', 'number', 'integerOnly' => true, 'min' => 0],
93
     *     ['ip_3', 'number', 'integerOnly' => true, 'min' => 0],
94
     *     ['ip_4', 'number', 'integerOnly' => true, 'min' => 0],
95
     * ]
96
     * @return array
97
     */
98 58
    public function rules()
99
    {
100 58
        return $this->getEntityRules();
101
    }
102
103
    /**
104
     * Populate and return the entity behaviors.
105
     * You should call this function in your extended class and merge the result
106
     * with your behaviors, instead of overriding it, unless you know the
107
     * consequences.
108
     * @return array
109
     */
110 62
    public function behaviors()
111
    {
112 62
        return $this->getEntityBehaviors();
113
    }
114
115
    /**
116
     * Get cache component. If cache component is not configured, Yii::$app->cache
117
     * will be given.
118
     * @return Cache cache component.
119
     */
120 62
    protected function getCache()
121
    {
122 62
        $cacheId = $this->cacheId;
123 62
        return empty($cacheId) ? Yii::$app->cache : Yii::$app->$cacheId;
124
    }
125
126
    /**
127
     * Get entity rules cache key.
128
     * @return string cache key.
129
     */
130 58
    public function getEntityRulesCacheKey()
131
    {
132 58
        return static::className() . $this->cachePrefix . static::$cacheKeyEntityRules;
133
    }
134
135
    /**
136
     * Get entity rules cache tag.
137
     * @return string cache tag.
138
     */
139 17
    public function getEntityRulesCacheTag()
140
    {
141 17
        return static::className() . $this->cachePrefix . static::$cacheTagEntityRules;
142
    }
143
144
    /**
145
     * Get entity rules.
146
     * @return array rules.
147
     */
148 58
    public function getEntityRules()
149
    {
150 58
        $cache = $this->getCache();
151 58
        if ($cache) {
152 58
            $this->entityLocalRules = $cache->get($this->getEntityRulesCacheKey());
0 ignored issues
show
Documentation Bug introduced by
It seems like $cache->get($this->getEntityRulesCacheKey()) of type * is incompatible with the declared type array of property $entityLocalRules.

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...
153 58
        }
154 58
        if (empty($this->entityLocalRules) || !is_array($this->entityLocalRules)) {
155 17
            $rules = array_merge($this->getGuidRules(), $this->getIdRules(), $this->getCreatedAtRules(), $this->getUpdatedAtRules(), $this->getIpRules());
156 17
            $this->setEntityRules($rules);
157 17
        }
158 58
        return $this->entityLocalRules;
159
    }
160
161
    /**
162
     * Set entity rules.
163
     * @param array $rules
164
     */
165 17
    protected function setEntityRules($rules = [])
166
    {
167 17
        $this->entityLocalRules = $rules;
168 17
        $cache = $this->getCache();
169 17
        if ($cache) {
170 17
            $tagDependency = new TagDependency(
171 17
                ['tags' => [$this->getEntityRulesCacheTag()]]
172 17
            );
173 17
            $cache->set($this->getEntityRulesCacheKey(), $rules, 0, $tagDependency);
174 17
        }
175 17
    }
176
177
    /**
178
     * Get entity behaviors cache key.
179
     * @return string cache key.
180
     */
181 62
    public function getEntityBehaviorsCacheKey()
182
    {
183 62
        return static::className() . $this->cachePrefix . static::$cacheKeyEntityBehaviors;
184
    }
185
186
    /**
187
     * Get entity behaviors cache tag.
188
     * @return string cache tag.
189
     */
190 17
    public function getEntityBehaviorsCacheTag()
191
    {
192 17
        return static::className() . $this->cachePrefix . static::$cacheTagEntityBehaviors;
193
    }
194
195
    /**
196
     * Get the entity behaviors.
197
     * @return array
198
     */
199 62
    public function getEntityBehaviors()
200
    {
201 62
        $cache = $this->getCache();
202 62
        if ($cache) {
203 62
            $this->entityLocalBehaviors = $cache->get($this->getEntityBehaviorsCacheKey());
0 ignored issues
show
Documentation Bug introduced by
It seems like $cache->get($this->getEntityBehaviorsCacheKey()) of type * is incompatible with the declared type array of property $entityLocalBehaviors.

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...
204 62
        }
205 62
        if (empty($this->entityLocalBehaviors) || !is_array($this->entityLocalBehaviors)) {
206 17
            $this->setEntityBehaviors($this->getTimestampBehaviors());
207 17
        }
208 62
        return $this->entityLocalBehaviors;
209
    }
210
211
    /**
212
     * Set the entity behaviors.
213
     * @param array $behaviors
214
     */
215 17
    protected function setEntityBehaviors($behaviors)
216
    {
217 17
        $this->entityLocalBehaviors = $behaviors;
218 17
        $cache = $this->getCache();
219 17
        if ($cache) {
220 17
            $tagDependencyConfig = ['tags' => [$this->getEntityBehaviorsCacheTag()]];
221 17
            $tagDependency = new TagDependency($tagDependencyConfig);
222 17
            $cache->set($this->getEntityBehaviorsCacheKey(), $behaviors, 0, $tagDependency);
223 17
        }
224 17
    }
225
226
    /**
227
     * Reset cache key.
228
     * @param string $cacheKey
229
     * @param mixed $value
230
     * @return boolean whether the value is successfully stored into cache. if
231
     * cache component was not configured, then return false directly.
232
     */
233
    public function resetCacheKey($cacheKey, $value = false)
234
    {
235
        $cache = $this->getCache();
236
        if ($cache) {
237
            return $this->getCache()->set($cacheKey, $value);
238
        }
239
        return false;
240
    }
241
242
    /**
243
     * Attach events associated with entity model.
244
     */
245 62
    protected function initEntityEvents()
246
    {
247 62
        $this->on(static::EVENT_INIT, [$this, 'onInitCache']);
0 ignored issues
show
It seems like on() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
248 62
        $this->attachInitGuidEvent(static::$eventNewRecordCreated);
249 62
        $this->attachInitIdEvent(static::$eventNewRecordCreated);
250 62
        $this->attachInitIpEvent(static::$eventNewRecordCreated);
251 62
        if ($this->isNewRecord) {
0 ignored issues
show
The property isNewRecord does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
252 62
            $this->trigger(static::$eventNewRecordCreated);
0 ignored issues
show
It seems like trigger() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
253 62
        }
254 62
        $this->on(static::EVENT_AFTER_FIND, [$this, 'onRemoveExpired']);
0 ignored issues
show
It seems like on() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
255 62
    }
256
257
    /**
258
     * Initialize the cache prefix.
259
     * @param ModelEvent $event
260
     */
261 62
    public function onInitCache($event)
262
    {
263 62
        $sender = $event->sender;
264 62
        $data = $event->data;
265 62
        if (isset($data['prefix'])) {
266
            $sender->cachePrefix = $data['prefix'];
267
        } else {
268 62
            $sender->cachePrefix = $sender::className();
269
        }
270 62
    }
271
272
    /**
273
     * Record warnings.
274
     */
275
    protected function recordWarnings()
276
    {
277
        if (YII_ENV !== YII_ENV_PROD || YII_DEBUG) {
278
            Yii::warning($this->errors);
0 ignored issues
show
The property errors does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
279
        }
280
    }
281
282
    /**
283
     * Get guid or id. if neither disabled, return null.
284
     * @return string
285
     */
286 10
    public function __toString()
287
    {
288 10
        if (is_string($this->guidAttribute)) {
289 10
            return $this->guid;
290
        }
291
        if (is_string($this->idAttribute)) {
292
            return $this->id;
293
        }
294
        return null;
295
    }
296
297
    /**
298
     * @inheritdoc
299
     * -------------
300
     * if enable `$idAttribute` and $row[$idAttribute] set, the `idPreassigned`
301
     * will be assigned to true.
302
     */
303 44
    public static function instantiate($row)
304
    {
305 44
        $self = static::buildNoInitModel();
306 44
        if (isset($self->idAttribute) && isset($row[$self->idAttribute])) {
307 44
            $model = new static(['idPreassigned' => true]);
0 ignored issues
show
The call to EntityTrait::__construct() has too many arguments starting with array('idPreassigned' => true).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
308 44
        } else {
309 2
            $model = new static;
310
        }
311 44
        return $model;
312
    }
313
314
    /**
315
     * unset entity attributes.
316
     * @return array result.
317
     */
318
    public function unsetSelfFields()
319
    {
320
        return static::unsetFields($this->attributes, $this->enabledFields());
0 ignored issues
show
The property attributes does not seem to exist. Did you mean idAttributeSafe?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
321
    }
322
323
    /**
324
     * unset fields of array.
325
     * @param array $array
326
     * @param array $fields
327
     * @return array
328
     */
329
    public static function unsetFields($array, $fields = null)
330
    {
331
        if (!is_array($array)) {
332
            $fields = [];
333
        }
334
        foreach ($array as $key => $value) {
335
            if (is_string($key) && in_array($key, $fields)) {
336
                unset($array[$key]);
337
            }
338
        }
339
        return $array;
340
    }
341
342
    /**
343
     * Get enabled fields.
344
     * @return string[]
345
     */
346 16
    public function enabledFields()
347
    {
348 16
        return array_merge(
349 16
            is_string($this->guidAttribute) ? [$this->guidAttribute] : [],
350 16
            is_string($this->idAttribute) ? [$this->idAttribute] : [],
351 16
            $this->enabledTimestampFields(),
352 16
            $this->enabledIPFields()
353 16
        );
354
    }
355
}
356