Completed
Push — work-fleets ( 5c3a01...351cf4 )
by SuperNova.WS
06:40
created

EntityContainer::processRow()   B

Complexity

Conditions 7
Paths 9

Size

Total Lines 20
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 7
eloc 13
nc 9
nop 2
dl 0
loc 20
rs 8.2222
c 3
b 0
f 0
ccs 0
cts 16
cp 0
crap 56
1
<?php
2
3
/**
4
 * Class EntityContainer
5
 *
6
 * Introduces linked models and export/import operations
7
 *
8
 * Importer is a callable like
9
 *    function ($that, &$row[, $propertyName[, $fieldName]]) {}
10
 *
11
 * Exporter is a callable like
12
 *    function ($that, &$row[, $propertyName[, $fieldName]]) {}
13
 */
14
class EntityContainer extends ContainerAccessors {
15
  /**
16
   * Property list and description
17
   *
18
   * propertyName => array(
19
   *    P_DB_FIELD => 'dbFieldName', - directly converts property to field and vice versa
20
   * )
21
   *
22
   * @var array[] $properties
23
   */
24
  protected $properties = array();
25
26
27
  /**
28
   * Set properties data from external source
29
   *
30
   * @param array $properties
31
   */
32
  public function setProperties($properties) {
33
    $this->properties = $properties;
34
  }
35
36
  /**
37
   * @param array  $row
38
   * @param string $processor
39
   */
40
  protected function processRow(&$row, $processor) {
41
    foreach ($this->properties as $propertyName => $propertyData) {
42
      $fieldName = !empty($propertyData[P_DB_FIELD]) ? $propertyData[P_DB_FIELD] : '';
43
      if (
44
        !empty($this->accessors[$propertyName][$processor])
45
        &&
46
        is_callable($this->accessors[$propertyName][$processor])
47
      ) {
48
        call_user_func_array($this->accessors[$propertyName][$processor], array($this, &$row, $propertyName, $fieldName));
0 ignored issues
show
Security Code Execution introduced by
$this->accessors[$propertyName][$processor] can contain request data and is used in code execution context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_POST
    in includes/general.php on line 258
  2. sys_get_param() returns tainted data
    in includes/general.php on line 290
  3. Data is passed through strip_tags(), and Data is passed through trim()
    in vendor/includes/general.php on line 1303
  4. sys_get_param_str_unsafe() returns tainted data, and BuddyParams::$request_text_unsafe is assigned
    in includes/classes/Buddy/BuddyParams.php on line 35
  5. Tainted property BuddyParams::$request_text_unsafe is read
    in includes/classes/Buddy/BuddyModel.php on line 254
  6. $params->request_text_unsafe is passed to ContainerAccessors::__set()
    in includes/classes/Buddy/BuddyModel.php on line -1
  7. ContainerAccessors::$accessors is assigned
    in includes/classes/ContainerAccessors.php on line 118
  8. Tainted property ContainerAccessors::$accessors is read
    in includes/classes/EntityContainer.php on line 48

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
49
      } elseif ($fieldName) {
50
        if ($processor == P_CONTAINER_IMPORT) {
51
          $this->$propertyName = $row[$fieldName];
52
        } else {
53
          $row[$fieldName] = $this->$propertyName;
54
        }
55
      }
56
      // Otherwise it's internal field - filled and used internally
57
    }
58
59
  }
60
61
  /**
62
   * Import DB row state into object properties
63
   *
64
   * @param array $row
65
   */
66
  public function importRow($row) {
67
    $this->clearProperties();
68
69
    if (is_array($row) && !empty($row)) {
70
      $this->processRow($row, P_CONTAINER_IMPORT);
71
    }
72
73
    return true;
74
  }
75
76
  /**
77
   * Exports object properties to DB row state WITHOUT ID
78
   *
79
   * Useful for INSERT operations
80
   *
81
   * @return array
82
   */
83
  public function exportRow() {
84
    $row = array();
85
    $this->processRow($row, P_CONTAINER_EXPORT);
86
87
    return $row;
88
  }
89
90
  public function isEmpty() {
91
    return empty($this->dbId);
0 ignored issues
show
Documentation introduced by
The property dbId does not exist on object<EntityContainer>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
92
  }
93
94
  public function isNew() {
95
    return empty($this->dbId);
0 ignored issues
show
Documentation introduced by
The property dbId does not exist on object<EntityContainer>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
96
  }
97
98
  /**
99
   * Clears only properties which declared in $properties array
100
   */
101
  public function clearProperties() {
102
    foreach ($this->properties as $propertyName => $propertyData) {
103
      unset($this->$propertyName);
104
    }
105
  }
106
107
}
108