Completed
Push — master ( 6b7717...ad9af1 )
by Alexandre
11s
created

core-functions.php ➔ reflect_args()   C

Complexity

Conditions 12
Paths 120

Size

Total Lines 53
Code Lines 34

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 31
CRAP Score 12.6144

Importance

Changes 0
Metric Value
cc 12
eloc 34
nc 120
nop 3
dl 0
loc 53
ccs 31
cts 37
cp 0.8378
crap 12.6144
rs 5.7718
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @author Todd Burry <[email protected]>
4
 * @copyright 2009-2014 Vanilla Forums Inc.
5
 * @license MIT
6
 */
7
8
/**
9
 * This file is part of the array_column library
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 *
14
 * @copyright Copyright (c) 2013 Ben Ramsey <http://benramsey.com>
15
 * @license http://opensource.org/licenses/MIT MIT
16
 */
17
18
/**
19
 * Returns the values from a single column of the input array, identified by the $columnKey.
20
 *
21
 * Optionally, you may provide an $indexKey to index the values in the returned
22
 * array by the values from the $indexKey column in the input array.
23
 *
24
 * @param array $array A multi-dimensional array (record set) from which to pull a column of values.
25
 * @param int|string|null $columnKey The column of values to return.
26
 * This value may be the integer key of the column you wish to retrieve, or it
27
 * may be the string key name for an associative array.
28
 * @param mixed $indexKey The column to use as the index/keys for the returned array.
29
 * This value may be the integer key of the column, or it may be the string key name.
30
 * @return array Returns an array of values representing a single column from the input array.
31
 * @category Array Functions
32
 */
33
function array_column_php(array $array, $columnKey = null, $indexKey = null) {
34 46 View Code Duplication
    if (!is_int($columnKey)
35 46
        && !is_float($columnKey)
36 46
        && !is_string($columnKey)
37 46
        && $columnKey !== null
38 46
        && !(is_object($columnKey) && method_exists($columnKey, '__toString'))
39 46
    ) {
40 2
        trigger_error('array_column(): The column key should be either a string or an integer', E_USER_WARNING);
41
    }
42
43 44 View Code Duplication
    if (isset($indexKey)
44 44
        && !is_int($indexKey)
45 44
        && !is_float($indexKey)
46 44
        && !is_string($indexKey)
47 44
        && !(is_object($indexKey) && method_exists($indexKey, '__toString'))
48 44
    ) {
49 1
        trigger_error('array_column(): The index key should be either a string or an integer', E_USER_WARNING);
50
    }
51
52 43
    $paramsColumnKey = ($columnKey !== null) ? (string)$columnKey : null;
53
54 43
    $paramsIndexKey = null;
55 43
    if (isset($indexKey)) {
56 2
        if (is_float($indexKey) || is_int($indexKey)) {
57 1
            $paramsIndexKey = (int)$indexKey;
58 1
        } else {
59 1
            $paramsIndexKey = (string)$indexKey;
60
        }
61 2
    }
62
63 43
    $resultArray = array();
64
65 43
    foreach ($array as $row) {
66
67 43
        $key = $value = null;
68 43
        $keySet = $valueSet = false;
69
70 43
        if ($paramsIndexKey !== null && array_key_exists($paramsIndexKey, $row)) {
71 2
            $keySet = true;
72 2
            $key = (string)$row[$paramsIndexKey];
73 2
        }
74
75 43
        if ($paramsColumnKey === null) {
76 1
            $valueSet = true;
77 1
            $value = $row;
78 43
        } elseif (is_array($row) && array_key_exists($paramsColumnKey, $row)) {
79 43
            $valueSet = true;
80 43
            $value = $row[$paramsColumnKey];
81 43
        }
82
83 43
        if ($valueSet) {
84 43
            if ($keySet) {
85 2
                $resultArray[$key] = $value;
86 2
            } else {
87 42
                $resultArray[] = $value;
88
            }
89 43
        }
90
91 43
    }
92
93 43
    return $resultArray;
94
}
95
96
if (!function_exists('array_column')) {
97
    /**
98
     * A custom implementation of array_column for older versions of php.
99
     *
100
     * @param array $array The dataset to test.
101
     * @param int|string $columnKey The column of values to return.
102
     * @param int|string|null $indexKey The column to use as the index/keys for the returned array.
103
     * @return array Returns the columns from the {@link $input} array.
104
     */
105
    function array_column($array, $columnKey, $indexKey = null) {
106 40
        return array_column_php($array, $columnKey, $indexKey);
107
    }
108
}
109
110
/**
111
 * Converts a quick array into a key/value form.
112
 *
113
 * @param array $array The array to work on.
114
 * @param mixed $default The default value for unspecified keys.
115
 * @return array Returns the array converted to long syntax.
116
 */
117 View Code Duplication
function array_quick(array $array, $default) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
118 35
    $result = [];
119 35
    foreach ($array as $key => $value) {
120 35
        if (is_int($key)) {
121 35
            $result[$value] = $default;
122 35
        } else {
123
            $result[$key] = $value;
124
        }
125 35
    }
126 35
    return $result;
127
}
128
129
/**
130
 * Converts a quick array into a key/value form using a callback to convert the short items.
131
 *
132
 * @param array $array The array to work on.
133
 * @param callable $callback The callback used to generate the default values.
134
 * @return array Returns the array converted to long syntax.
135
 */
136 View Code Duplication
function array_uquick(array $array, callable $callback) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
137
    $result = [];
138
    foreach ($array as $key => $value) {
139
        if (is_int($key)) {
140
            $result[$value] = $callback($value);
141
        } else {
142
            $result[$key] = $value;
143
        }
144
    }
145
    return $result;
146
}
147
148
/**
149
 * Load configuration data from a file into an array.
150
 *
151
 * @param string $path The path to load the file from.
152
 * @param string $php_var The name of the php variable to load from if using the php file type.
153
 * @return array The configuration data.
154
 * @throws InvalidArgumentException Throws an exception when the file type isn't supported.
155
 *
156
 * @category Array Functions
157
 */
158
function array_load($path, $php_var = 'config') {
159 11
    if (!file_exists($path)) {
160 5
        return false;
161
    }
162
163
    // Get the extension of the file, but allow for .ini.php, .json.php etc.
164 6
    $ext = strstr(basename($path), '.');
165
166
    switch ($ext) {
167
//            case '.ini':
168
//            case '.ini.php':
169
//                $loaded = parse_ini_file($path, false, INI_SCANNER_RAW);
170
//                break;
171 6
        case '.json':
172 6
        case '.json.php':
173 2
            $loaded = json_decode(file_get_contents($path), true);
174 2
            break;
175 4
        case '.php':
176 1
            include $path;
177 1
            $loaded = $$php_var;
178 1
            break;
179 3
        case '.ser':
180 3
        case '.ser.php':
181 2
            $loaded = unserialize(file_get_contents($path));
182 2
            break;
183 1
        case '.yml':
184 1
        case '.yml.php':
185
            $loaded = yaml_parse_file($path);
186
            break;
187 1
        default:
188 1
            throw new InvalidArgumentException("Invalid config extension $ext on $path.", 500);
189 1
    }
190 5
    return $loaded;
191
}
192
193
/**
194
 * Save an array of data to a specified path.
195
 *
196
 * @param array $data The data to save.
197
 * @param string $path The path to save to.
198
 * @param string $php_var The name of the php variable to load from if using the php file type.
199
 * @return bool Returns true if the save was successful or false otherwise.
200
 * @throws InvalidArgumentException Throws an exception when the file type isn't supported.
201
 *
202
 * @category Array Functions
203
 */
204
function array_save($data, $path, $php_var = 'config') {
205 7
    if (!is_array($data)) {
206
        throw new \InvalidArgumentException('Config::saveArray(): Argument #1 is not an array.', 500);
207
    }
208
209
    // Get the extension of the file, but allow for .ini.php, .json.php etc.
210 7
    $ext = strstr(basename($path), '.');
211
212
    switch ($ext) {
213
//            case '.ini':
214
//            case '.ini.php':
215
//                $ini = static::iniEncode($config);
216
//                $result = file_put_contents_safe($path, $ini);
217
//                break;
218 7
        case '.json':
219 7
        case '.json.php':
220 3
            if (defined('JSON_PRETTY_PRINT')) {
221 3
                $json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
222 3
            } else {
223
                $json = json_encode($data);
224
            }
225 3
            $result = file_put_contents_safe($path, $json);
226 3
            break;
227 4
        case '.php':
228 1
            $php = "<?php\n".php_encode($data, $php_var)."\n";
229 1
            $result = file_put_contents_safe($path, $php);
230 1
            break;
231 3
        case '.ser':
232 3
        case '.ser.php':
233 2
            $ser = serialize($data);
234 2
            $result = file_put_contents_safe($path, $ser);
235 2
            break;
236 1
        case '.yml':
237 1
        case '.yml.php':
238
            $yml = yaml_emit($data, YAML_UTF8_ENCODING, YAML_LN_BREAK);
239
            $result = file_put_contents_safe($path, $yml);
240
            break;
241 1
        default:
242 1
            throw new \InvalidArgumentException("Invalid config extension $ext on $path.", 500);
243 1
    }
244 6
    return $result;
245
}
246
247
/**
248
 * Search an array for a value with a user-defined comparison function.
249
 *
250
 * @param mixed $needle The value to search for.
251
 * @param array $haystack The array to search.
252
 * @param callable $cmp The comparison function to use in the search.
253
 * @return mixed|false Returns the found value or false if the value is not found.
254
 */
255
function array_usearch($needle, array $haystack, callable $cmp) {
256 32
    $found = array_uintersect($haystack, [$needle], $cmp);
257
258 32
    if (empty($found)) {
259 2
        return false;
260
    } else {
261 30
        return array_pop($found);
262
    }
263
}
264
265
/**
266
 * Select the first non-empty value from an array.
267
 *
268
 * @param array $keys An array of keys to try.
269
 * @param array $array The array to select from.
270
 * @param mixed $default The default value if non of the keys exist.
271
 * @return mixed Returns the first non-empty value of {@link $default} if none are found.
272
 * @category Array Functions
273
 */
274
function array_select(array $keys, array $array, $default = null) {
275 70
    foreach ($keys as $key) {
276 70
        if (isset($array[$key]) && $array[$key]) {
277 69
            return $array[$key];
278
        }
279 70
    }
280 3
    return $default;
281
}
282
283
/**
284
 * Make sure that a key exists in an array.
285
 *
286
 * @param string|int $key The array key to ensure.
287
 * @param array &$array The array to modify.
288
 * @param mixed $default The default value to set if key does not exist.
289
 * @category Array Functions
290
 */
291
function array_touch($key, &$array, $default) {
292 46
    if (!array_key_exists($key, $array)) {
293 45
        $array[$key] = $default;
294 45
    }
295 46
}
296
297
/**
298
 * Take all of the items in an array and make a new array with them specified by mappings.
299
 *
300
 * @param array $array The input array to translate.
301
 * @param array $mappings The mappings to translate the array.
302
 * @return array
303
 *
304
 * @category Array Functions
305
 */
306
function array_translate($array, $mappings) {
307 49
    $array = (array)$array;
308 49
    $result = array();
309 49
    foreach ($mappings as $index => $value) {
310 49
        if (is_numeric($index)) {
311 32
            $key = $value;
312 32
            $newKey = $value;
313 32
        } else {
314 35
            $key = $index;
315 35
            $newKey = $value;
316
        }
317 49
        if (isset($array[$key])) {
318 49
            $result[$newKey] = $array[$key];
319 49
        } else {
320 47
            $result[$newKey] = null;
321
        }
322 49
    }
323 49
    return $result;
324
}
325
326
/**
327
 * Returns the average rating based in the Wilson score interval.
328
 *
329
 *
330
 * @param int $positive The number of positive ratings.
331
 * @param int $total The total number of ratings.
332
 * @param float $confidence Your confidence level.
333
 * @return int
334
 *
335
 * @see http://stackoverflow.com/questions/9478741/mysql-php-for-wilson-score-interval-with-time-gravity
336
 * @see http://evanmiller.org/how-not-to-sort-by-average-rating.html
337
 */
338
//function averageRating($positive, $total, $confidence = 0.95) {
339
//   if ($total == 0)
340
//      return 0;
341
//
342
//   if ($confidence == 0.95)
343
//      $z = 1.96;
344
//   else
345
//      $z = pnormaldist(1 - (1 - $confidence) / 2, 0, 1);
346
//   $p = 1.0 * $positive / $total;
347
//   $s = ($p + $z * $z / (2 * $total) - $z * sqrt(($p * (1 - $p) + $z * $z / (4 * $total)) / $total)) / (1 + $z * $z / $total);
348
//   return $s;
349
//}
350
351
/**
352
 * Base64 Encode a string, but make it suitable to be passed in a url.
353
 *
354
 * @param string $str The string to encode.
355
 * @return string Returns the encoded string.
356
 * @category String Functions
357
 * @see base64_urldecode()
358
 * @see base64_encode()
359
 */
360
function base64url_encode($str) {
361 5
    return trim(strtr(base64_encode($str), '+/', '-_'), '=');
362
}
363
364
/**
365
 * Decode a string that was encoded using {@link base64_urlencode()}.
366
 *
367
 * @param string $str The encoded string.
368
 * @return string The decoded string.
369
 * @category String Functions
370
 * @see base64_urldecode()
371
 * @see base64_decode()
372
 */
373
function base64url_decode($str) {
374 5
    return base64_decode(strtr($str, '-_', '+/'));
375
}
376
377
/**
378
 * An alias of {@link config()}.
379
 *
380
 * @param string $key The config key.
381
 * @param string $default The default value if the config setting isn't available.
382
 * @return string The config value.
383
 * @see config()
384
 */
385
function c($key, $default) {
386
    return config($key, $default);
387
}
388
389
//function checkRoute($className, $methodName, &$routed) {
390
//   if ($routed)
391
//      return false;
392
//   if (class_exists($className) && method_exists($className, $methodName))
393
//      return $routed = true;
394
//   return $routed = false;
395
//}
396
397
/**
398
 * Get a value from the config.
399
 *
400
 * @param string $key The config key.
401
 * @param mixed $default The default value if the config setting isn't available.
402
 * @return mixed The config value.
403
 */
404
function config($key, $default = null) {
405
    return Garden\Config::get($key, $default);
406
}
407
408
/**
409
 * Compare two dates formatted as either timestamps or strings.
410
 *
411
 * @param mixed $date1 The first date to compare expressed as an integer timestamp or a string date.
412
 * @param mixed $date2 The second date to compare expressed as an integer timestamp or a string date.
413
 * @return int Returns `1` if {@link $date1} > {@link $date2}, `-1` if {@link $date1} > {@link $date2},
414
 * or `0` if the two dates are equal.
415
 * @category Date/Time Functions
416
 */
417
function datecmp($date1, $date2) {
418 1
    if (is_numeric($date1)) {
419 1
        $timestamp1 = $date1;
420 1
    } else {
421 1
        $timestamp1 = strtotime($date1);
422
    }
423
424 1
    if (is_numeric($date2)) {
425 1
        $timestamp2 = $date2;
426 1
    } else {
427 1
        $timestamp2 = strtotime($date2);
428
    }
429
430 1
    if ($timestamp1 == $timestamp2) {
431 1
        return 0;
432 1
    } elseif ($timestamp1 > $timestamp2) {
433 1
        return 1;
434
    } else {
435 1
        return -1;
436
    }
437
}
438
439
/**
440
 * Mark something as deprecated.
441
 *
442
 * When passing the {@link $name} argument, try using the following naming convention for names.
443
 *
444
 * - Functions: function_name()
445
 * - Classes: ClassName
446
 * - Static methods: ClassName::methodName()
447
 * - Instance methods: ClassName->methodName()
448
 *
449
 * @param string $name The name of the deprecated function.
450
 * @param string $newname The name of the new function that should be used instead.
451
 */
452
function deprecated($name, $newname = '') {
453
    $msg = $name.' is deprecated.';
454
    if ($newname) {
455
        $msg .= " Use $newname instead.";
456
    }
457
458
    trigger_error($msg, E_USER_DEPRECATED);
459
}
460
461
/**
462
 * A version of file_put_contents() that is multi-thread safe.
463
 *
464
 * @param string $filename Path to the file where to write the data.
465
 * @param mixed $data The data to write. Can be either a string, an array or a stream resource.
466
 * @param int $mode The permissions to set on a new file.
467
 * @return boolean
468
 * @category Filesystem Functions
469
 * @see http://php.net/file_put_contents
470
 */
471
function file_put_contents_safe($filename, $data, $mode = 0644) {
472 7
    $temp = tempnam(dirname($filename), 'atomic');
473
474 7
    if (!($fp = @fopen($temp, 'wb'))) {
475
        $temp = dirname($filename).DIRECTORY_SEPARATOR.uniqid('atomic');
476
        if (!($fp = @fopen($temp, 'wb'))) {
477
            trigger_error("file_put_contents_safe() : error writing temporary file '$temp'", E_USER_WARNING);
478
            return false;
479
        }
480
    }
481
482 7
    fwrite($fp, $data);
483 7
    fclose($fp);
484
485 7
    if (!@rename($temp, $filename)) {
486 1
        @unlink($filename);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
487 1
        @rename($temp, $filename);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
488 1
    }
489
490 7
    @chmod($filename, $mode);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
491 7
    return true;
492
}
493
494
/**
495
 * Force a value into a boolean.
496
 *
497
 * @param mixed $value The value to force.
498
 * @return boolean Returns the boolean value of {@link $value}.
499
 * @category Type Functions
500
 */
501
function force_bool($value) {
502 12
    if (is_string($value)) {
503 12
        switch (strtolower($value)) {
504 12
            case 'disabled':
505 12
            case 'false':
506 12
            case 'no':
507 12
            case 'off':
508 12
            case '':
509 6
                return false;
510 7
        }
511 7
        return true;
512
    }
513 2
    return (bool)$value;
514
}
515
516
/**
517
 * Force a string to look like an ip address (v4).
518
 *
519
 * @param string $ip The ip string to look at.
520
 * @return string|null The ipv4 address or null if {@link $ip} is empty.
521
 */
522
function force_ipv4($ip) {
523 1
    if (!$ip) {
524
        return null;
525
    }
526
527 1
    if (strpos($ip, ',') !== false) {
528
        $ip = substr($ip, 0, strpos($ip, ','));
529
    }
530
531
    // Make sure we have a valid ip.
532 1
    if (preg_match('`(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})`', $ip, $m)) {
533 1
        $ip = $m[1];
534 1
    } elseif ($ip === '::1') {
535
        $ip = '127.0.0.1';
536
    } else {
537
        $ip = '0.0.0.0'; // unknown ip
538
    }
539 1
    return $ip;
540
}
541
542
/**
543
 * Force a value to be an integer.
544
 *
545
 * @param mixed $value The value to force.
546
 * @return int Returns the integer value of {@link $value}.
547
 * @category Type Functions
548
 */
549
function force_int($value) {
550 4
    if (is_string($value)) {
551 4
        switch (strtolower($value)) {
552 4
            case 'disabled':
553 4
            case 'false':
554 4
            case 'no':
555 4
            case 'off':
556 4
            case '':
557 1
                return 0;
558 4
            case 'enabled':
559 4
            case 'true':
560 4
            case 'yes':
561 4
            case 'on':
562 1
                return 1;
563 4
        }
564 4
    }
565 4
    return intval($value);
566
}
567
568
function garden_error_handler($number, $message, $file, $line, $args) {
569 6
    $error_reporting = error_reporting();
570
    // Ignore errors that are below the current error reporting level.
571 6
    if (($error_reporting & $number) != $number) {
572 1
        return false;
573
    }
574
575 5
    $backtrace = debug_backtrace();
576
577 5
    throw new Garden\Exception\ErrorException($message, $number, $file, $line, $args, $backtrace);
578
}
579
580
/**
581
 * Like {@link implode()}, but joins array keys and values.
582
 *
583
 * @param string $elemglue The string that separates each element of the array.
584
 * @param string $keyglue The string that separates keys and values.
585
 * @param array $pieces The array of strings to implode.
586
 * @return string Returns the imploded array as a string.
587
 *
588
 * @category Array Functions
589
 * @category String Functions
590
 */
591
function implode_assoc($elemglue, $keyglue, $pieces) {
592 32
    $result = '';
593
594 32
    foreach ($pieces as $key => $value) {
595 32
        if ($result) {
596 32
            $result .= $elemglue;
597 32
        }
598
599 32
        $result .= $key.$keyglue.$value;
600 32
    }
601 32
    return $result;
602
}
603
604
/**
605
 * Whether or not a string is a url in the form http://, https://, or //.
606
 *
607
 * @param string $str The string to check.
608
 * @return bool
609
 *
610
 * @category String Functions
611
 * @category Internet Functions
612
 */
613
function is_url($str) {
614 7
    if (!$str) {
615 1
        return false;
616
    }
617 6
    if (substr($str, 0, 2) == '//') {
618 1
        return true;
619
    }
620 5
    if (strpos($str, '://', 1) !== false) {
621 2
        return true;
622
    }
623 3
    return false;
624
}
625
626
/**
627
 * Strip a substring from the beginning of a string.
628
 *
629
 * @param string $mainstr The main string to look at (the haystack).
630
 * @param string $substr The substring to search trim (the needle).
631
 * @return string
632
 *
633
 * @category String Functions
634
 */
635
function ltrim_substr($mainstr, $substr) {
636 14
    if (strncasecmp($mainstr, $substr, strlen($substr)) === 0) {
637 14
        return substr($mainstr, strlen($substr));
638
    }
639 1
    return $mainstr;
640
}
641
642
/**
643
 * Get the file extension from a mime-type.
644
 *
645
 * @param string $mime The mime type.
646
 * @param string $ext If this argument is specified then this extension will be added to the list of known types.
647
 * @return string The file extension without the dot.
648
 * @category Internet Functions
649
 * @category String Functions
650
 */
651
function mime2ext($mime, $ext = null) {
652 2
    static $known = array('text/plain' => '.txt', 'image/jpeg' => '.jpg', 'application/rss+xml' => '.rss');
653 2
    $mime = strtolower($mime);
654
655 2
    if ($ext !== null) {
656 1
        $known[$mime] = '.'.ltrim($ext, '.');
657 1
    }
658
659 2
    if (array_key_exists($mime, $known)) {
660 2
        return $known[$mime];
661
    }
662
663
    // We don't know the mime type so we need to just return the second part as the extension.
664 1
    $result = trim(strrchr($mime, '/'), '/');
665
666 1
    if (substr($result, 0, 2) === 'x-') {
667 1
        $result = substr($result, 2);
668 1
    }
669
670 1
    return '.'.$result;
671
}
672
673
/**
674
 * Encode a php array nicely.
675
 *
676
 * @param array $data The data to encode.
677
 * @param string $php_var The name of the php variable.
678
 * @return string Returns a string of the encoded data.
679
 *
680
 * @category Array Functions
681
 */
682
function php_encode($data, $php_var = 'config') {
683 1
    if (is_array($data)) {
684 1
        $result = '';
685 1
        $lastHeading = '';
686 1
        foreach ($data as $key => $value) {
687
            // Figure out the heading.
688 1
            if (($pos = strpos($key, '.')) !== false) {
689
                $heading = str_replace(array("\n", "\r"), ' ', substr($key, 0, $pos));
690
            } else {
691 1
                $heading = substr($key, 0, 1);
692
            }
693
694 1
            if ($heading !== $lastHeading) {
695 1
                if (strlen($heading) === 1) {
696
                    // Don't emit single letter headings, but space them out.
697 1
                    $result .= "\n";
698 1
                } else {
699
                    $result .= "\n// ".$heading."\n";
700
                }
701 1
                $lastHeading = $heading;
702 1
            }
703
704 1
            $result .= '$'.$php_var.'['.var_export($key, true).'] = '.var_export($value, true).";\n";
705 1
        }
706 1
    } else {
707
        $result = "\$$php_var = ".var_export($data, true).";\n";
708
    }
709 1
    return $result;
710
}
711
712
/**
713
 * Reflect the arguments on a callback and returns them as an associative array.
714
 *
715
 * @param callable $callback A callback to the function.
716
 * @param array $args An array of arguments.
717
 * @param array $get An optional other array of arguments.
718
 * @return array The arguments in an associative array, in order ready to be passed to call_user_func_array().
719
 * @throws Exception Throws an exception when {@link callback} isn't a valid callback.
720
 * @category Type Functions
721
 */
722
function reflect_args(callable $callback, $args, $get = null) {
723 12
    if (is_array($get)) {
724 1
        $args = array_merge($get, $args);
725 1
    }
726 12
    $args = array_change_key_case($args);
727
728 12
    if (is_string($callback) || (is_object($callback) && $callback instanceof Closure)) {
729 11
        $meth = new ReflectionFunction($callback);
730 11
        $meth_name = $meth;
731 11
    } else {
732 1
        $meth = new ReflectionMethod($callback[0], $callback[1]);
733 1
        if (is_string($callback[0])) {
734 1
            $meth_name = $callback[0].'::'.$meth->getName();
735 1
        } else {
736 1
            $meth_name = get_class($callback[0]).'->'.$meth->getName();
737
        }
738
    }
739
740 12
    $meth_params = $meth->getParameters();
741
742 12
    $call_args = array();
743 12
    $missing_args = array();
744
745
    // Set all of the parameters.
746 12
    foreach ($meth_params as $index => $meth_param) {
747 8
        $param_name = $meth_param->getName();
748 8
        $param_namel = strtolower($param_name);
749
750 8
        if (isset($args[$param_namel])) {
751 8
            $param_value = $args[$param_namel];
752 8
        } elseif (isset($args[$index])) {
753 1
            $param_value = $args[$index];
754 3
        } elseif ($meth_param->isDefaultValueAvailable()) {
755 2
            $param_value = $meth_param->getDefaultValue();
756 2
        } else {
757
            $param_value = null;
758
            $missing_args[] = '$'.$param_name;
759
        }
760
761 8
        $call_args[$param_name] = $param_value;
762 12
    }
763
764
    // Add optional parameters so that methods that use get_func_args() will still work.
765 12
    for ($index = count($call_args); array_key_exists($index, $args); $index++) {
766
        $call_args[$index] = $args[$index];
767
    }
768
769 12
    if (count($missing_args) > 0) {
770
        trigger_error("$meth_name() expects the following parameters: ".implode(', ', $missing_args).'.', E_USER_NOTICE);
771
    }
772
773 12
    return $call_args;
774
}
775
776
/**
777
 * Strip a substring rom the end of a string.
778
 *
779
 * @param string $mainstr The main string to search (the haystack).
780
 * @param string $substr The substring to trim (the needle).
781
 * @return string Returns the trimmed string or {@link $mainstr} if {@link $substr} was not found.
782
 * @category String Functions
783
 */
784
function rtrim_substr($mainstr, $substr) {
785 2
    if (strcasecmp(substr($mainstr, -strlen($substr)), $substr) === 0) {
786 1
        return substr($mainstr, 0, -strlen($substr));
787
    }
788 2
    return $mainstr;
789
}
790
791
/**
792
 * Returns whether or not a string begins with another string.
793
 *
794
 * This function is not case-sensitive.
795
 *
796
 * @param string $haystack The string to test.
797
 * @param string $needle The substring to test against.
798
 * @return bool Whether or not `$string` begins with `$with`.
799
 * @category String Functions
800
 */
801
function str_begins($haystack, $needle) {
802 1
    return strncasecmp($haystack, $needle, strlen($needle)) === 0;
803
}
804
805
/**
806
 * Returns whether or not a string ends with another string.
807
 *
808
 * This function is not case-sensitive.
809
 *
810
 * @param string $haystack The string to test.
811
 * @param string $needle The substring to test against.
812
 * @return bool Whether or not `$string` ends with `$with`.
813
 * @category String Functions
814
 */
815
function str_ends($haystack, $needle) {
816 109
    return strcasecmp(substr($haystack, -strlen($needle)), $needle) === 0;
817
}
818
819
$translations = [];
820
821
/**
822
 * Translate a string.
823
 *
824
 * @param string $code The translation code.
825
 * @param string $default The default if the translation is not found.
826
 * @return string The translated string.
827
 *
828
 * @category String Functions
829
 * @category Localization Functions
830
 */
831
function t($code, $default = null) {
832 34
    global $translations;
833
834 34
    if (substr($code, 0, 1) === '@') {
835 2
        return substr($code, 1);
836 34
    } elseif (isset($translations[$code])) {
837 2
        return $translations[$code];
838 33
    } elseif ($default !== null) {
839 1
        return $default;
840
    } else {
841 33
        return $code;
842
    }
843
}
844
845
/**
846
 * A version of {@link sprintf()} That translates the string format.
847
 *
848
 * @param string $formatCode The format translation code.
849
 * @param mixed $arg1 The arguments to pass to {@link sprintf()}.
850
 * @return string The translated string.
851
 */
852
function sprintft($formatCode, $arg1 = null) {
853 33
    $args = func_get_args();
854 33
    $args[0] = t($formatCode);
855 33
    return call_user_func_array('sprintf', $args);
856
}
857
858
/**
859
 * Make sure that a directory exists.
860
 *
861
 * @param string $dir The name of the directory.
862
 * @param int $mode The file permissions on the folder if it's created.
863
 * @throws Exception Throws an exception when {@link $dir} is a file.
864
 * @category Filesystem Functions
865
 */
866
function touchdir($dir, $mode = 0777) {
867 1
    if (!file_exists($dir)) {
868 1
        mkdir($dir, $mode, true);
869 1
    } elseif (!is_dir($dir)) {
870
        throw new Exception("The specified directory already exists as a file. ($dir)", 400);
871
    }
872 1
}
873
874
/**
875
 * Safely get a value out of an array.
876
 *
877
 * This function will always return a value even if the array key doesn't exist.
878
 * The val() function is one of the biggest workhorses of Vanilla and shows up a lot throughout other code.
879
 * It's much preferable to use this function if your not sure whether or not an array key exists rather than
880
 * using @ error suppression.
881
 *
882
 * This function uses optimizations found in the [facebook libphputil library](https://github.com/facebook/libphutil).
883
 *
884
 * @param string|int $key The array key.
885
 * @param array|object $array The array to get the value from.
886
 * @param mixed $default The default value to return if the key doesn't exist.
887
 * @return mixed The item from the array or `$default` if the array key doesn't exist.
888
 * @category Array Functions
889
 */
890
function val($key, $array, $default = null) {
891 189
    if (is_array($array)) {
892
        // isset() is a micro-optimization - it is fast but fails for null values.
893 187
        if (isset($array[$key])) {
894 180
            return $array[$key];
895
        }
896
897
        // Comparing $default is also a micro-optimization.
898 154
        if ($default === null || array_key_exists($key, $array)) {
899 104
            return null;
900
        }
901 124
    } elseif (is_object($array)) {
902 1
        if (isset($array->$key)) {
903 1
            return $array->$key;
904
        }
905
906 1
        if ($default === null || property_exists($array, $key)) {
907 1
            return null;
908
        }
909 1
    }
910
911 124
    return $default;
912
}
913
914
/**
915
 * Return the value from an associative array.
916
 *
917
 * This function differs from val() in that $key can be an array that will be used to walk a nested array.
918
 *
919
 * @param array|string $keys The keys or property names of the value. This can be an array or dot-seperated string.
920
 * @param array|object $array The array or object to search.
921
 * @param mixed $default The value to return if the key does not exist.
922
 * @return mixed The value from the array or object.
923
 * @category Array Functions
924
 */
925
function valr($keys, $array, $default = null) {
926 12
    if (is_string($keys)) {
927 3
        $keys = explode('.', $keys);
928 3
    }
929
930 12
    $value = $array;
931 12
    for ($i = 0; $i < count($keys); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
932 12
        $SubKey = $keys[$i];
933
934 12
        if (is_array($value) && isset($value[$SubKey])) {
935 9
            $value = $value[$SubKey];
936 12
        } elseif (is_object($value) && isset($value->$SubKey)) {
937 2
            $value = $value->$SubKey;
938 2
        } else {
939 6
            return $default;
940
        }
941 10
    }
942 10
    return $value;
943
}
944