Issues (2)

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/mp.php (2 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
namespace mp;
4
5
use Nayjest\StrCaseConverter\Str;
6
use ReflectionClass;
7
8
define('MP_USE_SETTERS', 1);
9
define('MP_CREATE_PROPERTIES', 2);
10
11
/**
12
 * Creates class instance using specified constructor arguments.
13
 *
14
 * @param string $class
15
 * @param array $arguments
16
 * @return object
17
 */
18
function instantiate($class, array $arguments = [])
19
{
20 2
    switch (count($arguments)) {
21 2
        case 0:
22 1
            return new $class();
23 1
        case 1:
24 1
            return new $class(array_shift($arguments));
25 1
        case 2:
26 1
            return new $class(
27 1
                array_shift($arguments),
28 1
                array_shift($arguments)
29 1
            );
30 1
        case 3:
31 1
            return new $class(
32 1
                array_shift($arguments),
33 1
                array_shift($arguments),
34 1
                array_shift($arguments)
35 1
            );
36 1
    }
37 1
    $reflection = new ReflectionClass($class);
38 1
    return $reflection->newInstanceArgs($arguments);
39
}
40
41
/**
42
 * Assigns values from array to existing public properties of target object.
43
 *
44
 * By default this function ignores fields having no corresponding properties in target object,
45
 * but this behavior can be changed if TRUE will be passed to third argument.
46
 *
47
 * @param object $targetObject target object
48
 * @param array $fields fields to assign, keys must be same as target object property names
49
 * @param bool $createProperties (optional, default value: false)
50
 *                               allows to create new properties in target object if value is true
51
 * @return string[] names of successfully assigned properties
52
 */
53
function setPublicProperties($targetObject, array $fields, $createProperties = false)
54
{
55 4
    if ($createProperties) {
56 1
        $overwrite = $fields;
57 1
    } else {
58 3
        $existing = get_object_vars($targetObject);
59 3
        $overwrite = array_intersect_key($fields, $existing);
60
    }
61 4
    foreach ($overwrite as $key => $value) {
62 3
        $targetObject->{$key} = $value;
63 4
    }
64 4
    return array_keys($overwrite);
65
}
66
67
/**
68
 * Assigns values from array to corresponding properties of target object using setters.
69
 *
70
 * This function works similar to mp\setPublicProperties(), but uses setter methods instead of public properties.
71
 *
72
 * Field names may be in snake or camel case,
73
 * it will be converted to camel case and prefixed by 'set'
74
 * to check availability of corresponding setter in target object.
75
 *
76
 * Fields having no corresponding setters in target object will be ignored.
77
 *
78
 * This function does not work with magic setters created using __set() php method.
79
 *
80
 * @param object $targetObject target object
81
 * @param array $fields fields to assign, keys are used to check availability of corresponding setters in target object
82
 * @return string[] names of successfully assigned properties
83
 */
84
function setValuesUsingSetters($targetObject, array $fields)
85
{
86 2
    $assignedProperties = [];
87 2
    foreach ($fields as $key => $value) {
88 2
        $methodName = 'set' . Str::toCamelCase($key);
89 2
        if (method_exists($targetObject, $methodName)) {
90 2
            $targetObject->$methodName($value);
91 2
            $assignedProperties[] = $key;
92 2
        }
93 2
    }
94 2
    return $assignedProperties;
95
}
96
97
/**
98
 * Assigns values from $fields array to $target. Target may be object or array.
99
 *
100
 * By default `mp\setValues` ignores fields having no corresponding properties or setters in target object
101
 * but this behavior can be changed if MP_CREATE_PROPERTIES option is used.
102
 *
103
 * Assigning values using setters can be disabled by removing MP_USE_SETTERS option (it's enabled by default).
104
 *
105
 * When target is an array, `mp\setValues` will call array_merge PHP function.
106
 *
107
 * @param object|array $target target object or array
108
 * @param array $fields fields to assign
109
 * @pram int $options (optional, default value: MP_USE_SETTERS) supported options: MP_USE_SETTERS, MP_CREATE_PROPERTIES
110
 * @return string[] names of successfully assigned properties
111
 */
112
function setValues(&$target, array $fields, $options = MP_USE_SETTERS)
113
{
114 3
    if (is_array($target)) {
115 2
        $target = array_merge($target, $fields);
116 2
        return array_keys($fields);
117
    }
118 1
    if ($options & MP_USE_SETTERS) {
119 1
        $assignedBySetters = setValuesUsingSetters(
120 1
            $target,
121
            $fields
122 1
        );
123 1
    } else {
124
        $assignedBySetters = [];
125
    }
126 1
    $assignedProperties = setPublicProperties(
127 1
        $target,
128 1
        array_diff_key($fields, array_flip($assignedBySetters)),
129
        $options & MP_CREATE_PROPERTIES
130 1
    );
131
132 1
    return array_merge($assignedProperties, $assignedBySetters);
133
}
134
135
/**
136
 * Returns names of writable properties for objects and classes or existing keys for arrays.
137
 *
138
 * Only public object properties and properties having setters considered writable.
139
 *
140
 * For setters, this function will return property names based on setter names
141
 * (setter names are converted to snake case, 'set' prefixes are removed).
142
 *
143
 * Detecting properties by setters can be disabled by specifying second argument as FALSE.
144
 *
145
 * @param object|string|array $target object or class name or array
146
 * @param bool $useSetters (optional, default value: true) if true, properties having setters will be added to results
147
 * @return string[] names of writable properties
148
 */
149
function getWritable($target, $useSetters = true)
150
{
151 1
    static $writable = [];
152
153 1
    if (is_array($target)) {
154 1
        return array_keys($target);
155
    }
156 1
    $class = is_object($target) ? get_class($target) : $target;
157 1
    $cacheKey = $class . ($useSetters ? '+s' : '');
158 1
    if (!array_key_exists($cacheKey, $writable)) {
159 1
        $writable[$cacheKey] = array_keys(get_class_vars($class));
160 1
        if ($useSetters) {
161 1
            $setters = getSetters($class);
162 1
            foreach ($setters as $setter) {
163 1
                $writable[$cacheKey][] = Str::toSnakeCase(substr($setter, 3));
164 1
            }
165 1
        }
166 1
    }
167 1
    return $writable[$cacheKey];
168
}
169
170
/**
171
 * Returns method names from target object/class that starts from specified keyword
172
 * and followed by uppercase character.
173
 *
174
 * Examples:
175
 *     - mp\getMethodsPrefixedBy('get', $obj)
176
 *       will return methods that looks like getters.
177
 *
178
 * @param string $keyword method name prefix
179
 * @param object|string $target object or class name
180
 * @return array|string[] method names
181
 */
182
function getMethodsPrefixedBy($keyword, $target)
183
{
184 3
    $res = [];
185 3
    $methods = get_class_methods($target);
186 3
    $keyLength = strlen($keyword);
187 3
    foreach ($methods as $method) {
188
        if (
189 3
            strpos($method, $keyword) === 0
190 3
            && strlen($method) > $keyLength
191 3
            && ctype_upper($method[$keyLength])
192 3
        ) {
193 3
            $res[] = $method;
194 3
        }
195 3
    }
196 3
    return $res;
197
}
198
199
/**
200
 * Returns method names from target object/class that looks like setters.
201
 *
202
 * @param object|string $target object or class name
203
 * @return string[] method names
204
 */
205
function getSetters($target)
206
{
207 2
    return getMethodsPrefixedBy('set', $target);
208
}
209
210
/**
211
 * Returns method names from target object/class that looks like getters.
212
 *
213
 * @param object|string $target object or class name
214
 * @return array|string[] method names
215
 */
216
function getGetters($target)
217
{
218 1
    return getMethodsPrefixedBy('get', $target);
219
}
220
221
/**
222
 * Returns values of properties specified in $propertyNames argument.
223
 *
224
 * This function supports getters, i. e.
225
 * value returned by getSomeValue() method of target object can be requested as 'some_value' property.
226
 *
227
 * @experimental
228
 *
229
 * @param object|array $src
230
 * @param string[] $propertyNames
231
 * @return array
232
 */
233
function getValues($src, array $propertyNames)
234
{
235
236 1
    if (is_array($src)) {
237 1
        return array_intersect_key($src, array_flip($propertyNames));
238
    }
239 1
    $values = array_intersect_key(get_object_vars($src), array_flip($propertyNames));
240 1
    foreach ($propertyNames as $key) {
241 1
        if (array_key_exists($key, $values)) continue;
242 1
        $getter = 'get' . Str::toCamelCase($key);
243 1
        if (method_exists($src, $getter)) {
244 1
            $values[$key] = $src->{$getter}();
245 1
        }
246 1
    }
247 1
    return $values;
248
}
249
250
/**
251
 * Extracts value specified by property / field name from object or array.
252
 *
253
 * This function supports property paths (prop1.prop2.prop3) and getters.
254
 *
255
 * If $propertyName = 'prop_name', this method will try to extract data in following order from:
256
 * - $src['prop_name']
257
 * - $src->prop_name
258
 * - $src->getPropName()
259
 * - $src->prop_name()
260
 * - $src->isPropName()
261
 *
262
 * @experimental
263
 * @param array|object $src
264
 * @param string $propertyName
265
 * @param mixed $default default value
266
 * @param string|null $delimiter (optional, default value: '.') used to specify property paths
267
 * @return mixed
268
 */
269
function getValue($src, $propertyName, $default = null, $delimiter = '.')
270
{
271 2
    return getValueByRef($src, $propertyName, $default, $delimiter);
272
}
273
274
/**
275
 * Extracts value specified by property / field / method name from object or array by reference if possible.
276
 *
277
 * This function acts like `mp\getValue` with only difference that value will be returned by reference if possible.
278
 *
279
 * @experimental
280
 * @param array|object $src
281
 * @param string $propertyName
282
 * @param mixed $default
283
 * @param string|null $delimiter
284
 * @return mixed|null
285
 */
286
function &getValueByRef(&$src, $propertyName, $default = null, $delimiter = '.')
287
{
288 2
    if (is_array($src) && array_key_exists($propertyName, $src)) {        
289 2
        return $src[$propertyName];
290
    }
291 2
    $isObject = is_object($src);
292 2
    if ($isObject && isset($src->{$propertyName})) {        
293
        // if it's not magic method, return reference
294 1
        if (property_exists($src, $propertyName)) {
295 1
            return $src->{$propertyName};
296
            // otherwise (it's __get()) calling $src->{$propertyName} will generate PHP notice:
297
            // indirect modification of overloaded property has no effect.
298
            // Therefore we return link to temp variable instead of link to variable itself.
299
        } else {
300
            $tmp = $src->{$propertyName};
301
            return $tmp;
302
        }
303
    }    
304 2
    if ($delimiter && $pos = strpos($propertyName, $delimiter)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $delimiter of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
305
        // head(a.b.c) = a
306
        // tail(a.b.c) = b.c
307 2
        $head = substr($propertyName, 0, $pos);
308 2
        $tail = substr($propertyName, $pos + 1);
309 2
        return getValueByRef(
310 2
            getValueByRef($src, $head, $default, null),
311 2
            $tail,
312 2
            $default,
313
            $delimiter
314 2
        );
315
    }
316 2
    if ($isObject) {
317 1
        $camelPropName = Str::toCamelCase($propertyName);
318
        $methods = [
319 1
            'get' . $camelPropName,
320 1
            $propertyName,
321 1
            $camelPropName,
322
            'is' . $camelPropName
323 1
        ];
324 1
        foreach ($methods as $method) {
325 1
            if (method_exists($src, $method)) {
326 1
                $result = call_user_func([$src, $method]);
327 1
                return $result;
328
            }
329 1
        }
330 1
    }
331 2
    return $default;
332
}
333
334
/**
335
 * Assigns value, supports property paths (prop1.prop2.prop3).
336
 *
337
 * @experimental
338
 * @param array|object $target
339
 * @param string $propertyName
340
 * @param mixed $value
341
 * @param string|null $delimiter
342
 * @return bool returns TRUE if value was successfully assigned, FALSE otherwise
343
 */
344
function setValue(&$target, $propertyName, $value, $delimiter = '.')
345
{
346 1
    if ($delimiter && $pos = strrpos($propertyName, $delimiter)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $delimiter of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
347
        // head(a.b.c) = a.b
348
        // tail(a.b.c) = c
349 1
        $head = substr($propertyName, 0, $pos);
350 1
        $tail = substr($propertyName, $pos + 1);
351 1
        $container = &getValueByRef($target, $head, null, $delimiter);
352 1
        if (!$container) {
353 1
            return false;
354
        }
355 1
        $res = setValues($container, [$tail => $value]);
356 1
        return count($res) === 1;
357
    }
358 1
    $res = setValues($target, [$propertyName => $value]);
359 1
    return count($res) === 1;
360
}
361