Passed
Push — master ( c41426...132167 )
by Lee
05:49
created

BuiltinOperations::keyGetFunc()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 3
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 1
rs 10
1
<?php
2
0 ignored issues
show
Coding Style introduced by
Missing file doc comment
Loading history...
3
declare(strict_types=1);
4
5
namespace Casbin\Util;
6
7
use Casbin\Rbac\RoleManager;
8
use Closure;
9
use Exception;
10
use IPTools\IP;
11
use IPTools\Range;
12
13
/**
14
 * Class BuiltinOperations.
15
 *
16
 * @author [email protected]
0 ignored issues
show
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
17
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
18
class BuiltinOperations
19
{
20
    /**
21
     * Determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
22
     * For example, "/foo/bar" matches "/foo/*".
23
     *
24
     * @param string $key1
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
25
     * @param string $key2
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
26
     *
27
     * @return bool
28
     */
29 18
    public static function keyMatch(string $key1, string $key2): bool
30
    {
31 18
        if (false === strpos($key2, '*')) {
32 18
            return $key1 == $key2;
33
        }
34
35 18
        $needle = rtrim($key2, '*');
36
37 18
        return substr($key1, 0, \strlen($needle)) === (string)$needle;
38
    }
39
40
    /**
41
     * The wrapper for KeyMatch.
42
     *
43
     * @param mixed ...$args
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
44
     *
45
     * @return bool
46
     */
47 15
    public static function keyMatchFunc(...$args): bool
48
    {
49 15
        $name1 = $args[0];
50 15
        $name2 = $args[1];
51
52 15
        return self::keyMatch($name1, $name2);
53
    }
54
55
    /**
56
     * KeyGet returns the matched part
57
     * For example, "/foo/bar/foo" matches "/foo/*"
58
     * "bar/foo" will been returned
59
     *
60
     * @param string $key1
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
61
     * @param string $key2
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
62
     * @return string
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
63
     */
64 3
    public static function keyGet(string $key1, string $key2): string
65
    {
66 3
        $i = strpos($key2, '*');
67 3
        if ($i === false) {
68 3
            return "";
69
        }
70 3
        if (strlen($key1) > $i) {
71 3
            if (substr($key1, 0, $i) == substr($key2, 0, $i)) {
72 3
                return substr($key1, $i);
73
            }
74
        }
75 3
        return '';
76
    }
77
78
    /**
79
     * KeyGetFunc is the wrapper for KeyGet
80
     *
81
     * @param mixed ...$args
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
82
     * @return string
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
83
     */
84 3
    public static function keyGetFunc(...$args)
85
    {
86 3
        $name1 = $args[0];
87 3
        $name2 = $args[1];
88
89 3
        return self::keyGet($name1, $name2);
90
    }
91
92
    /**
93
     * Determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
94
     * For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/:resource".
95
     *
96
     * @param string $key1
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
97
     * @param string $key2
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
98
     *
99
     * @return bool
100
     */
101 24
    public static function keyMatch2(string $key1, string $key2): bool
102
    {
103 24
        if ('*' === $key2) {
104 12
            $key2 = '.*';
105
        }
106 24
        $key2 = str_replace(['/*'], ['/.*'], $key2);
107
108 24
        $pattern = '/:[^\/]+/';
109
110 24
        $key2 = preg_replace_callback(
111 24
            $pattern,
112 8
            function ($m) {
0 ignored issues
show
Unused Code introduced by
The parameter $m is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

112
            function (/** @scrutinizer ignore-unused */ $m) {

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

Loading history...
113 24
                return '[^\/]+';
114 24
            },
115 16
            $key2
116
        );
117
118 24
        return self::regexMatch($key1, '^' . $key2 . '$');
119
    }
120
121
    /**
122
     * The wrapper for KeyMatch2.
123
     *
124
     * @param mixed ...$args
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
125
     *
126
     * @return bool
127
     */
128 9
    public static function keyMatch2Func(...$args): bool
129
    {
130 9
        $name1 = $args[0];
131 9
        $name2 = $args[1];
132
133 9
        return self::keyMatch2($name1, $name2);
134
    }
135
136
    /**
137
     * KeyGet2 returns value matched pattern
138
     * For example, "/resource1" matches "/:resource"
139
     * if the pathVar == "resource", then "resource1" will be returned
140
     *
141
     * @param string $key1
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
142
     * @param string $key2
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
143
     * @param string $pathVar
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
144
     * @return string
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
145
     */
146 3
    public static function keyGet2(string $key1, string $key2, string $pathVar): string
147
    {
148 3
        $key2 = str_replace(['/*'], ['/.*'], $key2);
149
150 3
        $pattern = '/:[^\/]+/';
151 3
        $keys = [];
152 3
        preg_match_all($pattern, $key2, $keys);
153 3
        $keys = $keys[0];
154 3
        $key2 = preg_replace_callback(
155 3
            $pattern,
156 1
            function ($m) {
0 ignored issues
show
Unused Code introduced by
The parameter $m is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

156
            function (/** @scrutinizer ignore-unused */ $m) {

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

Loading history...
157 3
                return '([^\/]+)';
158 3
            },
159 2
            $key2
160
        );
161
162 3
        $key2 = "~^" . $key2 . "$~";
163 3
        $values = [];
164 3
        preg_match($key2, $key1, $values);
165
166 3
        if (count($values) === 0) {
167 3
            return '';
168
        }
169 3
        foreach ($keys as $i => $key) {
170 3
            if ($pathVar == substr($key, 1)) {
171 3
                return $values[$i + 1];
172
            }
173
        }
174 3
        return '';
175
    }
176
177
    /**
178
     * KeyGet2Func is the wrapper for KeyGet2
179
     *
180
     * @param mixed ...$args
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
181
     * @return string
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
182
     */
183 3
    public static function keyGet2Func(...$args)
184
    {
185 3
        $name1 = $args[0];
186 3
        $name2 = $args[1];
187 3
        $key   = $args[2];
188
189 3
        return self::keyGet2($name1, $name2, $key);
190
    }
191
192
    /**
193
     * Determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
194
     * For example, "/foo/bar" matches "/foo/*", "/resource1" matches "/{resource}".
195
     *
196
     * @param string $key1
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
197
     * @param string $key2
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
198
     *
199
     * @return bool
200
     */
201 6
    public static function keyMatch3(string $key1, string $key2): bool
202
    {
203 6
        $key2 = str_replace(['/*'], ['/.*'], $key2);
204
205 6
        $pattern = '/\{[^\/]+\}/';
206 6
        $key2 = preg_replace_callback(
207 6
            $pattern,
208 2
            function ($m) {
0 ignored issues
show
Unused Code introduced by
The parameter $m is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

208
            function (/** @scrutinizer ignore-unused */ $m) {

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

Loading history...
209 6
                return '[^\/]+';
210 6
            },
211 4
            $key2
212
        );
213
214 6
        return self::regexMatch($key1, '^' . $key2 . '$');
215
    }
216
217
    /**
218
     * The wrapper for KeyMatch3.
219
     *
220
     * @param mixed ...$args
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
221
     *
222
     * @return bool
223
     */
224 3
    public static function keyMatch3Func(...$args): bool
225
    {
226 3
        $name1 = $args[0];
227 3
        $name2 = $args[1];
228
229 3
        return self::keyMatch3($name1, $name2);
230
    }
231
232
    /**
233
     * Determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
234
     * Besides what KeyMatch3 does, KeyMatch4 can also match repeated patterns:
235
     * "/parent/123/child/123" matches "/parent/{id}/child/{id}"
236
     * "/parent/123/child/456" does not match "/parent/{id}/child/{id}"
237
     * But KeyMatch3 will match both.
238
     *
239
     * @param string $key1
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
240
     * @param string $key2
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
241
     *
242
     * @return bool
243
     */
244 3
    public static function keyMatch4(string $key1, string $key2): bool
245
    {
246 3
        $key2 = str_replace(['/*'], ['/.*'], $key2);
247
248 3
        $tokens = [];
249 3
        $pattern = '/\{([^\/]+)\}/';
250 3
        $key2 = preg_replace_callback(
251 3
            $pattern,
252 1
            function ($m) use (&$tokens) {
253 3
                $tokens[] = $m[1];
254
255 3
                return '([^\/]+)';
256 3
            },
257 2
            $key2
258
        );
259
260 3
        $matched = preg_match_all('~^' . $key2 . '$~', $key1, $matches);
261 3
        if (!$matched) {
262 3
            return false;
263
        }
264
265 3
        $values = [];
266 3
        foreach ($tokens as $key => $token) {
267 3
            if (!isset($values[$token])) {
268 3
                $values[$token] = $matches[$key + 1];
269
            }
270 3
            if ($values[$token] != $matches[$key + 1]) {
271 3
                return false;
272
            }
273
        }
274
275 3
        return true;
276
    }
277
278
    /**
279
     * The wrapper for KeyMatch4.
280
     *
281
     * @param mixed ...$args
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
282
     *
283
     * @return bool
284
     */
285 3
    public static function keyMatch4Func(...$args): bool
286
    {
287 3
        $name1 = $args[0];
288 3
        $name2 = $args[1];
289
290 3
        return self::keyMatch4($name1, $name2);
291
    }
292
293
    /**
294
     * Determines whether key1 matches the pattern of key2 in regular expression.
295
     *
296
     * @param string $key1
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
297
     * @param string $key2
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
298
     *
299
     * @return bool
300
     */
301 39
    public static function regexMatch(string $key1, string $key2): bool
302
    {
303 39
        return (bool)preg_match('~' . $key2 . '~', $key1);
304
    }
305
306
    /**
307
     * The wrapper for RegexMatch.
308
     *
309
     * @param mixed ...$args
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
310
     *
311
     * @return bool
312
     */
313 21
    public static function regexMatchFunc(...$args): bool
314
    {
315 21
        $name1 = $args[0];
316 21
        $name2 = $args[1];
317
318 21
        return self::regexMatch($name1, $name2);
319
    }
320
321
    /**
322
     * Determines whether IP address ip1 matches the pattern of IP address ip2, ip2 can be an IP address or a CIDR
323
     * pattern.
324
     *
325
     * @param string $ip1
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
326
     * @param string $ip2
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
327
     *
328
     * @return bool
329
     *
330
     * @throws Exception
331
     */
332 6
    public static function ipMatch(string $ip1, string $ip2): bool
333
    {
334 6
        $objIP1 = IP::parse($ip1);
335
336 6
        $objIP2 = Range::parse($ip2);
337
338 6
        return $objIP2->contains($objIP1);
339
    }
340
341
    /**
342
     * The wrapper for IPMatch.
343
     *
344
     * @param mixed ...$args
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
345
     *
346
     * @return bool
347
     *
348
     * @throws Exception
349
     */
350 6
    public static function ipMatchFunc(...$args): bool
351
    {
352 6
        $ip1 = $args[0];
353 6
        $ip2 = $args[1];
354
355 6
        return self::ipMatch($ip1, $ip2);
356
    }
357
358
    /**
359
     * Returns true if the specified `string` matches the given glob `pattern`.
360
     *
361
     * @param string $str
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
362
     * @param string $pattern
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
363
     *
364
     * @return bool
365
     *
366
     * @throws Exception
367
     */
368 3
    public static function globMatch(string $str, string $pattern): bool
369
    {
370 3
        return fnmatch($pattern, $str, FNM_PATHNAME | FNM_PERIOD);
371
    }
372
373
    /**
374
     * The wrapper for globMatch.
375
     *
376
     * @param mixed ...$args
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
377
     *
378
     * @return bool
379
     *
380
     * @throws Exception
381
     */
382 3
    public static function globMatchFunc(...$args): bool
383
    {
384 3
        $str = $args[0];
385 3
        $pattern = $args[1];
386
387 3
        return self::globMatch($str, $pattern);
388
    }
389
390
    /**
391
     * The factory method of the g(_, _) function.
392
     *
393
     * @param RoleManager|null $rm
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
394
     *
395
     * @return Closure
396
     */
397 75
    public static function generateGFunction(RoleManager $rm = null): Closure
398
    {
399 25
        return function (...$args) use ($rm) {
400 75
            $name1 = $args[0];
401 75
            $name2 = $args[1];
402
403 75
            if (null === $rm) {
404 3
                return $name1 == $name2;
405 72
            } elseif (2 == \count($args)) {
406 60
                return $rm->hasLink($name1, $name2);
407
            } else {
408 12
                $domain = (string)$args[2];
409 12
                return $rm->hasLink($name1, $name2, $domain);
410
            }
411 75
        };
412
    }
413
}
414