Issues (199)

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.

src/models/BaseModel.php (1 issue)

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
 * BaseModel.php
4
 *
5
 * PHP version 5.6+
6
 *
7
 * @author Philippe Gaultier <[email protected]>
8
 * @copyright 2010-2017 Philippe Gaultier
9
 * @license http://www.sweelix.net/license license
10
 * @version 1.2.0
11
 * @link http://www.sweelix.net
12
 * @package sweelix\oauth2\server\models
13
 */
14
15
namespace sweelix\oauth2\server\models;
16
17
use sweelix\oauth2\server\interfaces\BaseModelInterface;
18
use yii\base\InvalidArgumentException;
19
use yii\base\Model;
20
use yii\base\ModelEvent;
21
use Yii;
22
use Exception;
23
use yii\base\NotSupportedException;
24
use yii\helpers\Inflector;
25
26
/**
27
 * This is the base model
28
 *
29
 * @author Philippe Gaultier <[email protected]>
30
 * @copyright 2010-2017 Philippe Gaultier
31
 * @license http://www.sweelix.net/license license
32
 * @version 1.2.0
33
 * @link http://www.sweelix.net
34
 * @package sweelix\oauth2\server\models
35
 * @since 1.0.0
36
 */
37
abstract class BaseModel extends Model implements BaseModelInterface
38
{
39
    /**
40
     * @var array|null old attribute values indexed by attribute names.
41
     * This is `null` if the record [[isNewRecord|is new]].
42
     */
43
    private $_oldAttributes;
44
45
    /**
46
     * @var array attribute values indexed by attribute names
47
     */
48
    private $_attributes = [];
49
50
    /**
51
     * @codeCoverageIgnore
52
     */
53
    protected static function getDataService()
54
    {
55
        throw new NotSupportedException('You must implement BaseModel::getDataService()');
56
    }
57
58
    /**
59
     * @return string attribute key of the object
60
     * @since 1.0.0
61
     */
62
    abstract public function key();
63
64
    /**
65
     * Definition of model attributes ['attributeName' => 'type', ...] where type can be :
66
     *   * bool
67
     *   * string
68
     *   * float
69
     *   * int
70
     * As database are not always able to retain datatype, this will be used by the service layer to
71
     * cast data
72
     * @return array definition of model attributes
73
     * @since 1.0.0
74
     */
75
    abstract public function attributesDefinition();
76
77
    /**
78
     * Returns the list of all attribute names of the model.
79
     * The default implementation will return all column names defined in scenario.
80
     * @return array list of attribute names.
81
     * @codeCoverageIgnore
82
     */
83
    public function attributes()
84
    {
85
        return array_keys($this->attributesDefinition());
86
    }
87
88
    /**
89
     * Initializes the object.
90
     * This method is called at the end of the constructor.
91
     * The default implementation will trigger an [[EVENT_INIT]] event.
92
     * If you override this method, make sure you call the parent implementation at the end
93
     * to ensure triggering of the event.
94
     */
95 53
    public function init()
96
    {
97 53
        parent::init();
98 53
        $this->trigger(self::EVENT_INIT);
99 53
    }
100
101
    /**
102
     * Repopulates this record with the latest data.
103
     * @return boolean whether the row still exists in the database. If true, the latest data
104
     * will be populated to this active record. Otherwise, this record will remain unchanged.
105
     */
106
    public function refresh()
107
    {
108
        $record = static::findOne($this->getKey());
109
        if ($record === null) {
110
            return false;
111
        }
112
        foreach ($this->attributes() as $name) {
113
            $this->_attributes[$name] = isset($record->_attributes[$name]) ? $record->_attributes[$name] : null;
114
        }
115
        $this->_oldAttributes = $this->_attributes;
116
        return true;
117
    }
118
119
    /**
120
     * Returns the key value of the object
121
     * @return mixed|null
122
     * @since 1.0.0
123
     */
124 49
    public function getKey()
125
    {
126 49
        $key = $this->key();
127 49
        return isset($this->_attributes[$key]) ? $this->_attributes[$key] : null;
128
    }
129
130
    /**
131
     * Returns the old key value of the object
132
     * @return mixed|null
133
     * @since 1.0.0
134
     */
135 20
    public function getOldKey()
136
    {
137 20
        $key = $this->key();
138 20
        return isset($this->_oldAttributes[$key]) ? $this->_oldAttributes[$key] : null;
139
    }
140
141
    /**
142
     * Returns a value indicating whether the model has an attribute with the specified name.
143
     * @param string $name the name of the attribute
144
     * @return boolean whether the model has an attribute with the specified name.
145
     */
146 49
    public function hasAttribute($name)
147
    {
148 49
        return isset($this->_attributes[$name]) || in_array($name, $this->attributes());
149
    }
150
    /**
151
     * Returns the named attribute value.
152
     * If this record is the result of a query and the attribute is not loaded,
153
     * null will be returned.
154
     * @param string $name the attribute name
155
     * @return mixed the attribute value. Null if the attribute is not set or does not exist.
156
     * @see hasAttribute()
157
     */
158
    public function getAttribute($name)
159
    {
160
        return isset($this->_attributes[$name]) ? $this->_attributes[$name] : null;
161
    }
162
    /**
163
     * Sets the named attribute value.
164
     * @param string $name the attribute name
165
     * @param mixed $value the attribute value.
166
     * @throws InvalidArgumentException if the named attribute does not exist.
167
     * @see hasAttribute()
168
     */
169 42
    public function setAttribute($name, $value)
170
    {
171 42
        if ($this->hasAttribute($name)) {
172 42
            $this->_attributes[$name] = $value;
173 42
        } else {
174
            throw new InvalidArgumentException(get_class($this) . ' has no attribute named "' . $name . '".');
175
        }
176 42
    }
177
178
    /**
179
     * Sets the old attribute values.
180
     * All existing old attribute values will be discarded.
181
     * @param array|null $values old attribute values to be set.
182
     * If set to `null` this record is considered to be [[isNewRecord|new]].
183
     */
184 49
    public function setOldAttributes($values)
185
    {
186 49
        $this->_oldAttributes = $values;
187 49
    }
188
189
    /**
190
     * Returns the old attribute values.
191
     * @return array the old attribute values (name-value pairs)
192
     */
193 9
    public function getOldAttributes()
194
    {
195 9
        return $this->_oldAttributes === null ? [] : $this->_oldAttributes;
196
    }
197
198
199
    /**
200
     * Sets the old value of the named attribute.
201
     * @param string $name the attribute name
202
     * @param mixed $value the old attribute value.
203
     * @throws InvalidArgumentException if the named attribute does not exist.
204
     * @see hasAttribute()
205
     */
206 9
    public function setOldAttribute($name, $value)
207
    {
208 9
        if (isset($this->_oldAttributes[$name]) || $this->hasAttribute($name)) {
209 9
            $this->_oldAttributes[$name] = $value;
210 9
        } else {
211
            throw new InvalidArgumentException(get_class($this) . ' has no attribute named "' . $name . '".');
212
        }
213 9
    }
214
215
    /**
216
     * Returns the old value of the named attribute.
217
     * If this record is the result of a query and the attribute is not loaded,
218
     * null will be returned.
219
     * @param string $name the attribute name
220
     * @return mixed the old attribute value. Null if the attribute is not loaded before
221
     * or does not exist.
222
     * @see hasAttribute()
223
     */
224
    public function getOldAttribute($name)
225
    {
226
        return isset($this->_oldAttributes[$name]) ? $this->_oldAttributes[$name] : null;
227
    }
228
229
    /**
230
     * Returns a value indicating whether the current record is new.
231
     * @return boolean whether the record is new and should be inserted when calling [[save()]].
232
     */
233 49
    public function getIsNewRecord()
234
    {
235 49
        return $this->_oldAttributes === null;
236
    }
237
    /**
238
     * Sets the value indicating whether the record is new.
239
     * @param boolean $value whether the record is new and should be inserted when calling [[save()]].
240
     * @see getIsNewRecord()
241
     */
242 12
    public function setIsNewRecord($value)
243
    {
244 12
        $this->_oldAttributes = $value ? null : $this->_attributes;
245 12
    }
246
247
    /**
248
     * Marks an attribute dirty.
249
     * This method may be called to force updating a record when calling [[update()]],
250
     * even if there is no change being made to the record.
251
     * @param string $name the attribute name
252
     */
253
    public function markAttributeDirty($name)
254
    {
255
        unset($this->_oldAttributes[$name]);
256
    }
257
258
    /**
259
     * Returns a value indicating whether the named attribute has been changed.
260
     * @param string $name the name of the attribute.
261
     * @param boolean $identical whether the comparison of new and old value is made for
262
     * identical values using `===`, defaults to `true`. Otherwise `==` is used for comparison.
263
     * This parameter is available since version 2.0.4.
264
     * @return boolean whether the attribute has been changed
265
     */
266
    public function isAttributeChanged($name, $identical = true)
267
    {
268
        if (isset($this->_attributes[$name], $this->_oldAttributes[$name])) {
269
            if ($identical) {
270
                return $this->_attributes[$name] !== $this->_oldAttributes[$name];
271
            } else {
272
                return $this->_attributes[$name] != $this->_oldAttributes[$name];
273
            }
274
        } else {
275
            return isset($this->_attributes[$name]) || isset($this->_oldAttributes[$name]);
276
        }
277
    }
278
279
280
    /**
281
     * Returns the attribute values that have been modified since they are loaded or saved most recently.
282
     *
283
     * The comparison of new and old values is made for identical values using `===`.
284
     *
285
     * @param string[]|null $names the names of the attributes whose values may be returned if they are
286
     * changed recently. If null, [[attributes()]] will be used.
287
     * @return array the changed attribute values (name-value pairs)
288
     */
289 49
    public function getDirtyAttributes($names = null)
290
    {
291 49
        if ($names === null) {
292 49
            $names = $this->attributes();
293 49
        }
294 49
        $names = array_flip($names);
295 49
        $attributes = [];
296 49
        if ($this->_oldAttributes === null) {
297 49
            foreach ($this->_attributes as $name => $value) {
298 49
                if (isset($names[$name])) {
299 49
                    $attributes[$name] = $value;
300 49
                }
301 49
            }
302 49
        } else {
303 9
            foreach ($this->_attributes as $name => $value) {
304 9
                if (isset($names[$name]) && (!array_key_exists($name, $this->_oldAttributes) || $value !== $this->_oldAttributes[$name])) {
305 9
                    $attributes[$name] = $value;
306 9
                }
307 9
            }
308
        }
309 49
        return $attributes;
310
    }
311
312
    /**
313
     * PHP getter magic method.
314
     * This method is overridden so that attributes and related objects can be accessed like properties.
315
     *
316
     * @param string $name property name
317
     * @throws \yii\base\InvalidArgumentException if relation name is wrong
318
     * @return mixed property value
319
     * @see getAttribute()
320
     */
321 49
    public function __get($name)
322
    {
323 49
        if (isset($this->_attributes[$name]) || array_key_exists($name, $this->_attributes)) {
324 49
            return $this->_attributes[$name];
325 38
        } elseif ($this->hasAttribute($name)) {
326 38
            return null;
327
        } else {
328
            return parent::__get($name);
329
        }
330
    }
331
    /**
332
     * PHP setter magic method.
333
     * This method is overridden so that AR attributes can be accessed like properties.
334
     * @param string $name property name
335
     * @param mixed $value property value
336
     */
337 49
    public function __set($name, $value)
338
    {
339 49
        if ($this->hasAttribute($name)) {
340 49
            $this->_attributes[$name] = $value;
341 49
        } else {
342
            parent::__set($name, $value);
343
        }
344 49
    }
345
    /**
346
     * Checks if a property value is null.
347
     * This method overrides the parent implementation by checking if the named attribute is null or not.
348
     * @param string $name the property name or the event name
349
     * @return boolean whether the property value is null
350
     */
351 30
    public function __isset($name)
352
    {
353
        try {
354 30
            return $this->__get($name) !== null;
355
        } catch (Exception $e) {
356
            return false;
357
        }
358
    }
359
    /**
360
     * Sets a component property to be null.
361
     * This method overrides the parent implementation by clearing
362
     * the specified attribute value.
363
     * @param string $name the property name or the event name
364
     */
365
    public function __unset($name)
366
    {
367
        if ($this->hasAttribute($name)) {
368
            unset($this->_attributes[$name]);
369
        } else {
370
            parent::__unset($name);
371
        }
372
    }
373
374
    /**
375
     * Populates the model with the data from end user.
376
     * The data to be loaded is `$data[formName]`, where `formName` refers to the value of [[formName()]].
377
     * If [[formName()]] is empty, the whole `$data` array will be used to populate the model.
378
     * The data being populated is subject to the safety check by [[setAttributes()]].
379
     * @param array $data the data array. This is usually `$_POST` or `$_GET`, but can also be any valid array
380
     * supplied by end user.
381
     * @param string $formName the form name to be used for loading the data into the model.
382
     * If not set, [[formName()]] will be used.
383
     * @return boolean whether the model is successfully populated with some data.
384
     */
385
    public function loadIds($data, $formName=null)
386
    {
387
        $camelData = [];
388
        foreach($data as $key => $value) {
389
            $key = lcfirst(Inflector::id2camel($key));
390
            $camelData[$key] = $value;
391
        }
392
        return parent::load($camelData, $formName);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (load() instead of loadIds()). Are you sure this is correct? If so, you might want to change this to $this->load().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
393
    }
394
395
    /**
396
     * This method is called when the AR object is created and populated with the query result.
397
     * The default implementation will trigger an [[EVENT_AFTER_FIND]] event.
398
     * When overriding this method, make sure you call the parent implementation to ensure the
399
     * event is triggered.
400
     */
401 42
    public function afterFind()
402
    {
403 42
        $this->trigger(self::EVENT_AFTER_FIND);
404 42
    }
405
406
    /**
407
     * This method is called at the beginning of inserting or updating a record.
408
     * The default implementation will trigger an [[EVENT_BEFORE_INSERT]] event when `$insert` is true,
409
     * or an [[EVENT_BEFORE_UPDATE]] event if `$insert` is false.
410
     * When overriding this method, make sure you call the parent implementation like the following:
411
     *
412
     * ```php
413
     * public function beforeSave($insert)
414
     * {
415
     *     if (parent::beforeSave($insert)) {
416
     *         // ...custom code here...
417
     *         return true;
418
     *     } else {
419
     *         return false;
420
     *     }
421
     * }
422
     * ```
423
     *
424
     * @param boolean $insert whether this method called while inserting a record.
425
     * If false, it means the method is called while updating a record.
426
     * @return boolean whether the insertion or updating should continue.
427
     * If false, the insertion or updating will be cancelled.
428
     */
429 49
    public function beforeSave($insert)
430
    {
431 49
        $event = new ModelEvent;
432 49
        $this->trigger($insert ? self::EVENT_BEFORE_INSERT : self::EVENT_BEFORE_UPDATE, $event);
433 49
        return $event->isValid;
434
    }
435
436
    /**
437
     * This method is called at the end of inserting or updating a record.
438
     * The default implementation will trigger an [[EVENT_AFTER_INSERT]] event when `$insert` is true,
439
     * or an [[EVENT_AFTER_UPDATE]] event if `$insert` is false. The event class used is [[AfterSaveEvent]].
440
     * When overriding this method, make sure you call the parent implementation so that
441
     * the event is triggered.
442
     * @param boolean $insert whether this method called while inserting a record.
443
     * If false, it means the method is called while updating a record.
444
     * @param array $changedAttributes The old values of attributes that had changed and were saved.
445
     * You can use this parameter to take action based on the changes made for example send an email
446
     * when the password had changed or implement audit trail that tracks all the changes.
447
     * `$changedAttributes` gives you the old attribute values while the active record (`$this`) has
448
     * already the new, updated values.
449
     */
450 49
    public function afterSave($insert, $changedAttributes)
451
    {
452 49
        $this->trigger($insert ? self::EVENT_AFTER_INSERT : self::EVENT_AFTER_UPDATE, new AfterSaveEvent([
453
            'changedAttributes' => $changedAttributes
454 49
        ]));
455 49
    }
456
457
    /**
458
     * This method is invoked before deleting a record.
459
     * The default implementation raises the [[EVENT_BEFORE_DELETE]] event.
460
     * When overriding this method, make sure you call the parent implementation like the following:
461
     *
462
     * ```php
463
     * public function beforeDelete()
464
     * {
465
     *     if (parent::beforeDelete()) {
466
     *         // ...custom code here...
467
     *         return true;
468
     *     } else {
469
     *         return false;
470
     *     }
471
     * }
472
     * ```
473
     *
474
     * @return boolean whether the record should be deleted. Defaults to true.
475
     */
476 12
    public function beforeDelete()
477
    {
478 12
        $event = new ModelEvent;
479 12
        $this->trigger(self::EVENT_BEFORE_DELETE, $event);
480 12
        return $event->isValid;
481
    }
482
    /**
483
     * This method is invoked after deleting a record.
484
     * The default implementation raises the [[EVENT_AFTER_DELETE]] event.
485
     * You may override this method to do postprocessing after the record is deleted.
486
     * Make sure you call the parent implementation so that the event is raised properly.
487
     */
488 12
    public function afterDelete()
489
    {
490 12
        $this->trigger(self::EVENT_AFTER_DELETE);
491 12
    }
492
}
493