GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — integration (#2571)
by Brendan
04:42
created

General::replacePlaceholdersWithContext()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 33
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 33
rs 6.7272
cc 7
eloc 12
nc 7
nop 3
1
<?php
2
/**
3
 * @package toolkit
4
 */
5
/**
6
 * General is a utility class that offers a number miscellaneous of
7
 * functions that are used throughout Symphony.
8
 */
9
10
class General
11
{
12
    /**
13
     * Convert any special characters into their entity equivalents. Since
14
     * Symphony 2.3, this function assumes UTF-8 and will not double
15
     * encode strings.
16
     *
17
     * @param string $source
18
     *  a string to operate on.
19
     * @return string
20
     *  the encoded version of the string.
21
     */
22
    public static function sanitize($source)
23
    {
24
        $source = htmlspecialchars($source, ENT_COMPAT, 'UTF-8', false);
25
26
        return $source;
27
    }
28
29
    /**
30
     * Revert any html entities to their character equivalents.
31
     *
32
     * @param string $str
33
     *  a string to operate on
34
     * @return string
35
     *  the decoded version of the string
36
     */
37
    public static function reverse_sanitize($str)
38
    {
39
        return htmlspecialchars_decode($str, ENT_COMPAT);
40
    }
41
42
    /**
43
     * Validate a string against a set of regular expressions.
44
     *
45
     * @param array|string $string
46
     *  string to operate on
47
     * @param array|string $rule
48
     *  a single rule or array of rules
49
     * @return boolean
50
     *  false if any of the rules in $rule do not match any of the strings in
51
     *  `$string`, return true otherwise.
52
     */
53
    public static function validateString($string, $rule)
54
    {
55
        if (!is_array($rule) && ($rule == '' || $rule == null)) {
56
            return true;
57
        }
58
59
        if (!is_array($string) && ($string == '' || $rule == null)) {
60
            return true;
61
        }
62
63
        if (!is_array($rule)) {
64
            $rule = array($rule);
65
        }
66
67
        if (!is_array($string)) {
68
            $string = array($string);
69
        }
70
71
        foreach ($rule as $r) {
72
            foreach ($string as $s) {
73
                if (!preg_match($r, $s)) {
74
                    return false;
75
                }
76
            }
77
        }
78
        return true;
79
    }
80
81
    /**
82
     * Replace the tabs with spaces in the input string.
83
     *
84
     * @param string $string
85
     *  the string in which to replace the tabs with spaces.
86
     * @param integer $spaces (optional)
87
     *  the number of spaces to replace each tab with. This argument is optional
88
     *  with a default of 4.
89
     * @return string
90
     *  the resulting string.
91
     */
92
    public static function tabsToSpaces($string, $spaces = 4)
93
    {
94
        return str_replace("\t", str_pad(null, $spaces), $string);
95
    }
96
97
    /**
98
     * Checks an xml document for well-formedness.
99
     *
100
     * @param string $data
101
     *  filename, xml document as a string, or arbitrary string
102
     * @param pointer &$errors
103
     *  pointer to an array which will contain any validation errors
104
     * @param boolean $isFile (optional)
105
     *  if this is true, the method will attempt to read from a file, `$data`
106
     *  instead.
107
     * @param mixed $xsltProcessor (optional)
108
     *  if set, the validation will be done using this XSLT processor rather
109
     *  than the built in XML parser. the default is null.
110
     * @param string $encoding (optional)
111
     *  if no XML header is expected, than this should be set to match the
112
     *  encoding of the XML
113
     * @return boolean
114
     *  true if there are no errors in validating the XML, false otherwise.
115
     */
116
    public static function validateXML($data, &$errors, $isFile = true, $xsltProcessor = null, $encoding = 'UTF-8')
117
    {
118
        $_data = ($isFile) ? file_get_contents($data) : $data;
119
        $_data = preg_replace('/<!DOCTYPE[-.:"\'\/\\w\\s]+>/', null, $_data);
120
121
        if (strpos($_data, '<?xml') === false) {
122
            $_data = '<?xml version="1.0" encoding="'.$encoding.'"?><rootelement>'.$_data.'</rootelement>';
123
        }
124
125
        if (is_object($xsltProcessor)) {
126
            $xsl = '<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
127
128
            <xsl:template match="/"></xsl:template>
129
130
            </xsl:stylesheet>';
131
132
            $xsltProcessor->process($_data, $xsl, array());
133
134
            if ($xsltProcessor->isErrors()) {
135
                $errors = $xsltProcessor->getError(true);
136
                return false;
137
            }
138
        } else {
139
            $_parser = xml_parser_create();
140
            xml_parser_set_option($_parser, XML_OPTION_SKIP_WHITE, 0);
141
            xml_parser_set_option($_parser, XML_OPTION_CASE_FOLDING, 0);
142
143
            if (!xml_parse($_parser, $_data)) {
144
                $errors = array('error' => xml_get_error_code($_parser) . ': ' . xml_error_string(xml_get_error_code($_parser)),
145
                                'col' => xml_get_current_column_number($_parser),
146
                                'line' => (xml_get_current_line_number($_parser) - 2));
147
                return false;
148
            }
149
150
            xml_parser_free($_parser);
151
        }
152
153
        return true;
154
    }
155
156
    /**
157
     * Check that a string is a valid URL.
158
     *
159
     * @param string $url
160
     *  string to operate on
161
     * @return string
162
     *  a blank string or a valid URL
163
     */
164
    public static function validateURL($url = null)
165
    {
166
        $url = trim($url);
167
168
        if (is_null($url) || $url == '') {
169
            return $url;
170
        }
171
172
        if (!preg_match('#^http[s]?:\/\/#i', $url)) {
173
            $url = 'http://' . $url;
174
        }
175
176
        include TOOLKIT . '/util.validators.php';
177
178
        if (!preg_match($validators['URI'], $url)) {
0 ignored issues
show
Bug introduced by
The variable $validators does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
179
            $url = '';
180
        }
181
182
        return $url;
183
    }
184
185
    /**
186
     * Strip any slashes from all array values.
187
     *
188
     * @param array &$arr
189
     *  Pointer to an array to operate on. Can be multi-dimensional.
190
     */
191
    public static function cleanArray(array &$arr)
192
    {
193
        foreach ($arr as $k => $v) {
194
            if (is_array($v)) {
195
                self::cleanArray($arr[$k]);
196
            } else {
197
                $arr[$k] = stripslashes($v);
198
            }
199
        }
200
    }
201
202
    /**
203
     * Flatten the input array. Any elements of the input array that are
204
     * themselves arrays will be removed and the contents of the removed array
205
     * inserted in its place. The keys for the inserted values will be the
206
     * concatenation of the keys in the original arrays in which it was embedded.
207
     * The elements of the path are separated by periods (.). For example,
208
     * given the following nested array structure:
209
     * `
210
     * array(1 =>
211
     *          array('key' => 'value'),
212
     *      2 =>
213
     *          array('key2' => 'value2', 'key3' => 'value3')
214
     *      )
215
     * `
216
     * will flatten to:
217
     * `array('1.key' => 'value', '2.key2' => 'value2', '2.key3' => 'value3')`
218
     *
219
     * @param array &$source
220
     *  The array to flatten, passed by reference
221
     * @param array &$output (optional)
222
     *  The array in which to store the flattened input, passed by reference.
223
     *  if this is not provided then a new array will be created.
224
     * @param string $path (optional)
225
     *  the current prefix of the keys to insert into the output array. this
226
     *  defaults to null.
227
     */
228
    public static function flattenArray(array &$source, &$output = null, $path = null)
229
    {
230
        if (is_null($output)) {
231
            $output = array();
232
        }
233
234
        foreach ($source as $key => $value) {
235
            if (is_int($key)) {
236
                $key = (string)($key + 1);
237
            }
238
239
            if (!is_null($path)) {
240
                $key = $path . '.' . (string)$key;
241
            }
242
243
            if (is_array($value)) {
244
                self::flattenArray($value, $output, $key);
245
            } else {
246
                $output[$key] = $value;
247
            }
248
        }
249
250
        $source = $output;
251
    }
252
253
    /**
254
     * Flatten the input array. Any elements of the input array that are
255
     * themselves arrays will be removed and the contents of the removed array
256
     * inserted in its place. The keys for the inserted values will be the
257
     * concatenation of the keys in the original arrays in which it was embedded.
258
     * The elements of the path are separated by colons (:). For example, given
259
     * the following nested array structure:
260
     * `
261
     * array(1 =>
262
     *          array('key' => 'value'),
263
     *      2 =>
264
     *          array('key2' => 'value2', 'key3' => 'value3')
265
     *      )
266
     * `
267
     * will flatten to:
268
     * `array('1:key' => 'value', '2:key2' => 'value2', '2:key3' => 'value3')`
269
     *
270
     *
271
     * @param array &$output
272
     *  The array in which to store the flattened input, passed by reference.
273
     * @param array &$source
274
     *  The array to flatten, passed by reference
275
     * @param string $path
276
     *  the current prefix of the keys to insert into the output array.
277
     */
278
    protected static function flattenArraySub(array &$output, array &$source, $path)
279
    {
280
        foreach ($source as $key => $value) {
281
            $key = $path . ':' . $key;
282
283
            if (is_array($value)) {
284
                self::flattenArraySub($output, $value, $key);
285
            } else {
286
                $output[$key] = $value;
287
            }
288
        }
289
    }
290
291
    /**
292
     * This method allows an array of variables with placeholders to replaced against
293
     * a given context. Any placeholders that don't exist in the context will be
294
     * left alone.
295
     *
296
     * @since Symphony 3.0
297
     * @param string $value (by reference)
298
     *  Placeholders will be replaced by inspecting the context eg. `{text}` will look
299
     *  for a `text` key in the `$context`. Dot notation supported, eg. `{date.format}`
300
     *  with this context `['date' => ['format' => 'value']]` will return `value`.
301
     * @param string $key
302
     * @param array $context
303
     */
304
    public static function replacePlaceholdersWithContext(&$value, $key, array $context)
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed.

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

Loading history...
305
    {
306
        // Check to see if there is replacement to occur
307
        if (preg_match_all('/{([^}]+)}/', $value, $matches, PREG_SET_ORDER)) {
308
            // Backup the original value and context so each match can use the
309
            // original set.
310
            $base_value = $value;
311
            $base_context = $context;
312
313
            // For each match, reset the context to the full stack
314
            foreach ($matches as $match) {
315
                $context = $base_context;
316
317
                // The '.' syntax is support for resolving arrays where each dot represents
318
                // another level. Each time we go down a level, we narrow the context accordingly.
319
                foreach (explode('.', $match[1]) as $segment) {
320
                    // If the segment exists in the context, narrow the context to the next level
321
                    // and allow the loop to continue.
322
                    if (is_array($context) && array_key_exists($segment, $context)) {
323
                        $context = $context[$segment];
324
                    }
325
326
                    // If the context has fully resolved to a string, replace the relevant
327
                    // match in the base value.
328
                    if (!is_array($context)) {
329
                        $base_value = str_replace('{'. $match[1] . '}', $context, $base_value);
330
                    }
331
                }
332
            }
333
334
            $value = $base_value;
335
        }
336
    }
337
338
    /**
339
     * Given a string, this will clean it for use as a Symphony handle. Preserves multi-byte characters.
340
     *
341
     * @since Symphony 2.2.1
342
     * @param string $string
343
     *  String to be cleaned up
344
     * @param integer $max_length
345
     *  The maximum number of characters in the handle
346
     * @param string $delim
347
     *  All non-valid characters will be replaced with this
348
     * @param boolean $uriencode
349
     *  Force the resultant string to be uri encoded making it safe for URLs
350
     * @param array $additional_rule_set
351
     *  An array of REGEX patterns that should be applied to the `$string`. This
352
     *  occurs after the string has been trimmed and joined with the `$delim`
353
     * @return string
354
     *  Returns resultant handle
355
     */
356
    public static function createHandle($string, $max_length = 255, $delim = '-', $uriencode = false, $additional_rule_set = null)
357
    {
358
        $max_length = intval($max_length);
359
360
        // make it lowercase
361
362
        $string = strtolower($string);
363
364
        // strip out tags
365
366
        $string = strip_tags($string);
367
368
        // remove unwanted characters
369
370
        $string = preg_replace('/[^\w- ]+/', ' ', $string);
371
372
        // consolidate whitespace
373
374
        $string = preg_replace('/[\s]+/', ' ', $string);
375
        $string = trim($string);
376
377
        // truncate if too long
378
379
        if (strlen($string) > $max_length) {
380
381
            $string = wordwrap($string, $max_length, '|');
382
            $string = substr($string, 0, strpos($string, '|'));
383
        }
384
385
        // replace whitespace with delimiter
386
387
        $string = str_replace(' ', $delim, $string);
388
389
        // apply additional rules
390
391
        if (is_array($additional_rule_set) && !empty($additional_rule_set)) {
392
393
            foreach ($additional_rule_set as $rule => $replacement) {
394
395
                $string = preg_replace($rule, $replacement, $string);
396
            }
397
        }
398
399
        // encode for URI use
400
401
        if ($uriencode) {
402
403
            $string = urlencode($string);
404
        }
405
406
        return $string;
407
    }
408
409
    /**
410
     * Given a string, this will clean it for use as a filename. Preserves multi-byte characters.
411
     *
412
     * @since Symphony 2.2.1
413
     * @param string $string
414
     *  String to be cleaned up
415
     * @param string $delim
416
     *  All non-valid characters will be replaced with this
417
     * @return string
418
     *  Returns created filename
419
     */
420
    public static function createFilename($string, $delim = '-')
421
    {
422
        // Strip out any tag
423
        $string = strip_tags($string);
424
425
        // Find all legal characters
426
        $count = preg_match_all('/[\p{L}\w:;.,+=~]+/u', $string, $matches);
427
        if ($count <= 0 || $count == false) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $count of type integer to the boolean false. If you are specifically checking for 0, consider using something more explicit like === 0 instead.
Loading history...
428
            preg_match_all('/[\w:;.,+=~]+/', $string, $matches);
429
        }
430
431
        // Join only legal character with the $delim
432
        $string = implode($delim, $matches[0]);
433
434
        // Remove leading or trailing delim characters
435
        $string = trim($string, $delim);
436
437
        // Make it lowercase
438
        $string = strtolower($string);
439
440
        return $string;
441
    }
442
443
    /**
444
     * Computes the length of the string.
445
     * This function will attempt to use PHP's `mbstring` functions if they are available.
446
     * This function also forces utf-8 encoding.
447
     *
448
     * @since Symphony 2.5.0
449
     * @param string $str
450
     *  the string to operate on
451
     * @return int
452
     *  the string's length
453
     */
454
    public static function strlen($str)
455
    {
456
        if (function_exists('mb_strlen')) {
457
            return mb_strlen($str, 'utf-8');
458
        }
459
        return strlen($str);
460
    }
461
462
    /**
463
     * Creates a sub string.
464
     * This function will attempt to use PHP's `mbstring` functions if they are available.
465
     * This function also forces utf-8 encoding.
466
     *
467
     * @since Symphony 2.5.0
468
     * @param string $str
469
     *  the string to operate on
470
     * @param int $start
471
     *  the starting offset
472
     * @param int $start
473
     *  the length of the substring
474
     * @return string
475
     *  the resulting substring
476
     */
477
    public static function substr($str, $start, $length)
478
    {
479
        if (function_exists('mb_substr')) {
480
            return mb_substr($str, $start, $length, 'utf-8');
481
        }
482
        return substr($str, $start, $length);
483
    }
484
485
    /**
486
     * Extract the first `$val` characters of the input string. If `$val`
487
     * is larger than the length of the input string then the original
488
     * input string is returned.
489
     *
490
     * @param string $str
491
     *  the string to operate on
492
     * @param integer $val
493
     *  the number to compare lengths with
494
     * @return string|boolean
495
     *  the resulting string or false on failure.
496
     */
497
    public static function substrmin($str, $val)
498
    {
499
        return(self::substr($str, 0, min(self::strlen($str), $val)));
500
    }
501
502
    /**
503
     * Extract the first `$val` characters of the input string. If
504
     * `$val` is larger than the length of the input string then
505
     * the original input string is returned
506
     *
507
     * @param string $str
508
     *  the string to operate on
509
     * @param integer $val
510
     *  the number to compare lengths with
511
     * @return string|boolean
512
     *  the resulting string or false on failure.
513
     */
514
    public static function substrmax($str, $val)
515
    {
516
        return(self::substr($str, 0, max(self::strlen($str), $val)));
517
    }
518
519
    /**
520
     * Extract the last `$num` characters from a string.
521
     *
522
     * @param string $str
523
     *  the string to extract the characters from.
524
     * @param integer $num
525
     *  the number of characters to extract.
526
     * @return string|boolean
527
     *  a string containing the last `$num` characters of the
528
     *  input string, or false on failure.
529
     */
530
    public static function right($str, $num)
531
    {
532
        $str = self::substr($str, self::strlen($str)-$num, $num);
533
        return $str;
534
    }
535
536
    /**
537
     * Extract the first `$num` characters from a string.
538
     *
539
     * @param string $str
540
     *  the string to extract the characters from.
541
     * @param integer $num
542
     *  the number of characters to extract.
543
     * @return string|boolean
544
     *  a string containing the last `$num` characters of the
545
     *  input string, or false on failure.
546
     */
547
    public static function left($str, $num)
548
    {
549
        $str = self::substr($str, 0, $num);
550
        return $str;
551
    }
552
553
    /**
554
     * Create all the directories as specified by the input path. If the current
555
     * directory already exists, this function will return true.
556
     *
557
     * @param string $path
558
     *  the path containing the directories to create.
559
     * @param integer $mode (optional)
560
     *  the permissions (in octal) of the directories to create. Defaults to 0755
561
     * @param boolean $silent (optional)
562
     *  true if an exception should be raised if an error occurs, false
563
     *  otherwise. this defaults to true.
564
     * @throws Exception
565
     * @return boolean
566
     */
567
    public static function realiseDirectory($path, $mode = 0755, $silent = true)
568
    {
569
        if (is_dir($path)) {
570
            return true;
571
        }
572
573
        try {
574
            $current_umask = umask(0);
575
            $success = @mkdir($path, intval($mode, 8), true);
576
            umask($current_umask);
577
578
            return $success;
579
        } catch (Exception $ex) {
580
            if ($silent === false) {
581
                throw new Exception(__('Unable to create path - %s', array($path)));
582
            }
583
584
            return false;
585
        }
586
    }
587
588
    /**
589
     * Recursively deletes all files and directories given a directory. This
590
     * function has two path. This function optionally takes a `$silent` parameter,
591
     * which when `false` will throw an `Exception` if there is an error deleting a file
592
     * or folder.
593
     *
594
     * @since Symphony 2.3
595
     * @param string $dir
596
     *  the path of the directory to delete
597
     * @param boolean $silent (optional)
598
     *  true if an exception should be raised if an error occurs, false
599
     *  otherwise. this defaults to true.
600
     * @throws Exception
601
     * @return boolean
602
     */
603
    public static function deleteDirectory($dir, $silent = true)
604
    {
605
        try {
606
            if (!file_exists($dir)) {
607
                return true;
608
            }
609
610
            if (!is_dir($dir)) {
611
                return unlink($dir);
612
            }
613
614
            foreach (scandir($dir) as $item) {
615
                if ($item == '.' || $item == '..') {
616
                    continue;
617
                }
618
619
                if (!self::deleteDirectory($dir.DIRECTORY_SEPARATOR.$item)) {
620
                    return false;
621
                }
622
            }
623
624
            return rmdir($dir);
625
        } catch (Exception $ex) {
626
            if ($silent === false) {
627
                throw new Exception(__('Unable to remove - %s', array($dir)));
628
            }
629
630
            return false;
631
        }
632
    }
633
634
    /**
635
     * Search a multi-dimensional array for a value.
636
     *
637
     * @param mixed $needle
638
     *  the value to search for.
639
     * @param array $haystack
640
     *  the multi-dimensional array to search.
641
     * @return boolean
642
     *  true if `$needle` is found in `$haystack`.
643
     *  true if `$needle` == `$haystack`.
644
     *  true if `$needle` is found in any of the arrays contained within `$haystack`.
645
     *  false otherwise.
646
     */
647
    public static function in_array_multi($needle, $haystack)
648
    {
649
        if ($needle == $haystack) {
650
            return true;
651
        }
652
653
        if (is_array($haystack)) {
654
            foreach ($haystack as $key => $val) {
655
                if (is_array($val)) {
656
                    if (self::in_array_multi($needle, $val)) {
657
                        return true;
658
                    }
659
                } elseif (!strcmp($needle, $key) || !strcmp($needle, $val)) {
660
                    return true;
661
                }
662
            }
663
        }
664
665
        return false;
666
    }
667
668
    /**
669
     * Search an array for multiple values.
670
     *
671
     * @param array $needles
672
     *  the values to search the `$haystack` for.
673
     * @param array $haystack
674
     *  the in which to search for the `$needles`
675
     * @return boolean
676
     *  true if any of the `$needles` are in `$haystack`,
677
     *  false otherwise.
678
     */
679
    public static function in_array_all($needles, $haystack)
680
    {
681
        foreach ($needles as $n) {
682
            if (!in_array($n, $haystack)) {
683
                return false;
684
            }
685
        }
686
687
        return true;
688
    }
689
690
    /**
691
     * Transform a multi-dimensional array to a flat array. The input array
692
     * is expected to conform to the structure of the `$_FILES` variable.
693
     *
694
     * @param array $filedata
695
     *  the raw `$_FILES` data structured array
696
     * @return array
697
     *  the flattened array.
698
     */
699
    public static function processFilePostData($filedata)
700
    {
701
        $result = array();
702
703
        foreach ($filedata as $key => $data) {
704
            foreach ($data as $handle => $value) {
705
                if (is_array($value)) {
706
                    foreach ($value as $index => $pair) {
707
                        if (!is_array($result[$handle][$index])) {
708
                            $result[$handle][$index] = array();
709
                        }
710
711
                        if (!is_array($pair)) {
712
                            $result[$handle][$index][$key] = $pair;
713
                        } else {
714
                            $result[$handle][$index][array_pop(array_keys($pair))][$key] = array_pop(array_values($pair));
0 ignored issues
show
Bug introduced by
array_keys($pair) cannot be passed to array_pop() as the parameter $array expects a reference.
Loading history...
Bug introduced by
array_values($pair) cannot be passed to array_pop() as the parameter $array expects a reference.
Loading history...
715
                        }
716
                    }
717
                } else {
718
                    $result[$handle][$key] = $value;
719
                }
720
            }
721
        }
722
723
        return $result;
724
    }
725
726
    /**
727
     * Merge `$_POST` with `$_FILES` to produce a flat array of the contents
728
     * of both. If there is no merge_file_post_data function defined then
729
     * such a function is created. This is necessary to overcome PHP's ability
730
     * to handle forms. This overcomes PHP's convoluted `$_FILES` structure
731
     * to make it simpler to access `multi-part/formdata`.
732
     *
733
     * @return array
734
     *  a flat array containing the flattened contents of both `$_POST` and
735
     *  `$_FILES`.
736
     */
737
    public static function getPostData()
0 ignored issues
show
Coding Style introduced by
getPostData uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
getPostData uses the super-global variable $_FILES which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
738
    {
739
        if (!function_exists('merge_file_post_data')) {
740
            function merge_file_post_data($type, array $file, &$post)
741
            {
742
                foreach ($file as $key => $value) {
743
                    if (!isset($post[$key])) {
744
                        $post[$key] = array();
745
                    }
746
747
                    if (is_array($value)) {
748
                        merge_file_post_data($type, $value, $post[$key]);
749
                    } else {
750
                        $post[$key][$type] = $value;
751
                    }
752
                }
753
            }
754
        }
755
756
        $files = array(
757
            'name'      => array(),
758
            'type'      => array(),
759
            'tmp_name'  => array(),
760
            'error'     => array(),
761
            'size'      => array()
762
        );
763
        $post = $_POST;
764
765
        if (is_array($_FILES) && !empty($_FILES)) {
766
            foreach ($_FILES as $key_a => $data_a) {
767
                if (!is_array($data_a)) {
768
                    continue;
769
                }
770
771
                foreach ($data_a as $key_b => $data_b) {
772
                    $files[$key_b][$key_a] = $data_b;
773
                }
774
            }
775
        }
776
777
        foreach ($files as $type => $data) {
778
            merge_file_post_data($type, $data, $post);
779
        }
780
781
        return $post;
782
    }
783
784
    /**
785
     * Find the next available index in an array. Works best with numeric keys.
786
     * The next available index is the minimum integer such that the array does
787
     * not have a mapping for that index. Uses the increment operator on the
788
     * index type of the input array, whatever that may do.
789
     *
790
     * @param array $array
791
     *  the array to find the next index for.
792
     * @param mixed $seed (optional)
793
     *  the object with which the search for an empty index is initialized. this
794
     *  defaults to null.
795
     * @return integer
796
     *  the minimum empty index into the input array.
797
     */
798
    public static function array_find_available_index($array, $seed = null)
799
    {
800
        if (!is_null($seed)) {
801
            $index = $seed;
802
        } else {
803
            $keys = array_keys($array);
804
            sort($keys);
805
            $index = array_pop($keys);
806
        }
807
808
        if (isset($array[$index])) {
809
            do {
810
                $index++;
811
            } while (isset($array[$index]));
812
        }
813
814
        return $index;
815
    }
816
817
    /**
818
     * Filter the duplicate values from an array into a new array, optionally
819
     * ignoring the case of the values (assuming they are strings?). A new array
820
     * is returned, the input array is left unchanged.
821
     *
822
     * @param array $array
823
     *  the array to filter.
824
     * @param boolean $ignore_case
825
     *  true if the case of the values in the array should be ignored, false otherwise.
826
     * @return array
827
     *  a new array containing only the unique elements of the input array.
828
     */
829
    public static function array_remove_duplicates(array $array, $ignore_case = false)
830
    {
831
        return ($ignore_case === true ? self::array_iunique($array) : array_unique($array));
832
    }
833
834
    /**
835
     * Test whether a value is in an array based on string comparison, ignoring
836
     * the case of the values.
837
     *
838
     * @param mixed $needle
839
     *  the object to search the array for.
840
     * @param array $haystack
841
     *  the array to search for the `$needle`.
842
     * @return boolean
843
     *  true if the `$needle` is in the `$haystack`, false otherwise.
844
     */
845
    public static function in_iarray($needle, array $haystack)
846
    {
847
        foreach ($haystack as $key => $value) {
848
            if (strcasecmp($value, $needle) == 0) {
849
                return true;
850
            }
851
        }
852
        return false;
853
    }
854
855
    /**
856
     * Filter the input array for duplicates, treating each element in the array
857
     * as a string and comparing them using a case insensitive comparison function.
858
     *
859
     * @param array $array
860
     *  the array to filter.
861
     * @return array
862
     *  a new array containing only the unique elements of the input array.
863
     */
864
    public static function array_iunique(array $array)
865
    {
866
        $tmp = array();
867
868
        foreach ($array as $key => $value) {
869
            if (!self::in_iarray($value, $tmp)) {
870
                $tmp[$key] = $value;
871
            }
872
        }
873
874
        return $tmp;
875
    }
876
877
    /**
878
     * Function recursively apply a function to an array's values.
879
     * This will not touch the keys, just the values.
880
     *
881
     * @since Symphony 2.2
882
     * @param string $function
883
     * @param array $array
884
     * @return array
885
     *  a new array with all the values passed through the given `$function`
886
     */
887
    public static function array_map_recursive($function, array $array)
888
    {
889
        $tmp = array();
890
891
        foreach ($array as $key => $value) {
892
            if (is_array($value)) {
893
                $tmp[$key] = self::array_map_recursive($function, $value);
894
            } else {
895
                $tmp[$key] = call_user_func($function, $value);
896
            }
897
        }
898
899
        return $tmp;
900
    }
901
902
    /**
903
     * Convert an array into an XML fragment and append it to an existing
904
     * XML element. Any arrays contained as elements in the input array will
905
     * also be recursively formatted and appended to the input XML fragment.
906
     * The input XML element will be modified as a result of calling this.
907
     *
908
     * @param XMLElement $parent
909
     *  the XML element to append the formatted array data to.
910
     * @param array $data
911
     *  the array to format and append to the XML fragment.
912
     * @param boolean $validate
913
     *  true if the formatted array data should be validated as it is
914
     *  constructed, false otherwise.
915
     */
916
    public static function array_to_xml(XMLElement $parent, array $data, $validate = false)
917
    {
918
        foreach ($data as $element_name => $value) {
919
            if (!is_numeric($value) && empty($value)) {
920
                continue;
921
            }
922
923
            if (is_int($element_name)) {
924
                $child = new XMLElement('item');
925
                $child->setAttribute('index', $element_name + 1);
926
            } else {
927
                $child = new XMLElement($element_name, null, array(), true);
928
            }
929
930
            if (is_array($value) || is_object($value)) {
931
                self::array_to_xml($child, (array)$value);
932
933
                if ($child->getNumberOfChildren() == 0) {
934
                    continue;
935
                }
936
            } elseif ($validate === true && !self::validateXML(self::sanitize($value), $errors, false, new XSLTProcess)) {
937
                continue;
938
            } else {
939
                $child->setValue(self::sanitize($value));
940
            }
941
942
            $parent->appendChild($child);
943
        }
944
    }
945
946
    /**
947
     * Create a file at the input path with the (optional) input permissions
948
     * with the input content. This function will ignore errors in opening,
949
     * writing, closing and changing the permissions of the resulting file.
950
     * If opening or writing the file fail then this will return false.
951
     * This method calls `clearstatcache()` in order to make sure we do not
952
     * hit the cache when checking for permissions.
953
     *
954
     * @param string $file
955
     *  the path of the file to write.
956
     * @param mixed $data
957
     *  the data to write to the file.
958
     * @param integer|null $perm (optional)
959
     *  the permissions as an octal number to set set on the resulting file.
960
     *  this defaults to 0644 (if omitted or set to null)
961
     * @param string $mode (optional)
962
     *  the mode that the file should be opened with, defaults to 'w'. See modes
963
     *  at http://php.net/manual/en/function.fopen.php
964
     * @param boolean $trim (optional)
965
     *  removes tripple linebreaks
966
     * @return boolean
967
     *  true if the file is successfully opened, written to, closed and has the
968
     *  required permissions set. false, otherwise.
969
     */
970
    public static function writeFile($file, $data, $perm = 0644, $mode = 'w', $trim = false)
971
    {
972
        clearstatcache();
973
974
        if (static::checkFile($file) === false) {
975
            return false;
976
        }
977
978
        if (!$handle = fopen($file, $mode)) {
979
            return false;
980
        }
981
982
        if ($trim === true) {
983
            $data = preg_replace("/(" . PHP_EOL . "([ |\t]+)?){2,}" . PHP_EOL . "/", PHP_EOL . PHP_EOL, trim($data));
984
        }
985
986
        if (fwrite($handle, $data, strlen($data)) === false) {
987
            return false;
988
        }
989
990
        fclose($handle);
991
992
        try {
993
            if (is_null($perm)) {
994
                $perm = 0644;
995
            }
996
997
            chmod($file, intval($perm, 8));
998
        } catch (Exception $ex) {
999
            // If we can't chmod the file, this is probably because our host is
1000
            // running PHP with a different user to that of the file. Although we
1001
            // can delete the file, create a new one and then chmod it, we run the
1002
            // risk of losing the file as we aren't saving it anywhere. For the immediate
1003
            // future, atomic saving isn't needed by Symphony and it's recommended that
1004
            // if your extension require this logic, it uses it's own function rather
1005
            // than this 'General' one.
1006
            return true;
1007
        }
1008
1009
        return true;
1010
    }
1011
1012
    /**
1013
     * Checks that the file and it's folder are readable and writable.
1014
     *
1015
     * @since Symphony 2.6.3
1016
     * @return boolean
1017
     */
1018
    public static function checkFile($file)
1019
    {
1020
        clearstatcache();
1021
        $dir = dirname($file);
1022
1023
        if (
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return !(!is_writable($d... !is_writable($file)));.
Loading history...
1024
            (!is_writable($dir) || !is_readable($dir)) // Folder
1025
            || (file_exists($file) && (!is_readable($file) || !is_writable($file))) // File
1026
        ) {
1027
            return false;
1028
        }
1029
1030
        return true;
1031
    }
1032
1033
    /**
1034
     * Delete a file at a given path, silently ignoring errors depending
1035
     * on the value of the input variable $silent.
1036
     *
1037
     * @param string $file
1038
     *  the path of the file to delete
1039
     * @param boolean $silent (optional)
1040
     *  true if an exception should be raised if an error occurs, false
1041
     *  otherwise. this defaults to true.
1042
     * @throws Exception
1043
     * @return boolean
1044
     *  true if the file is successfully unlinked, if the unlink fails and
1045
     *  silent is set to true then an exception is thrown. if the unlink
1046
     *  fails and silent is set to false then this returns false.
1047
     */
1048
    public static function deleteFile($file, $silent = true)
1049
    {
1050
        try {
1051
            return unlink($file);
1052
        } catch (Exception $ex) {
1053
            if ($silent === false) {
1054
                throw new Exception(__('Unable to remove file - %s', array($file)));
1055
            }
1056
1057
            return false;
1058
        }
1059
    }
1060
1061
    /**
1062
     * Extract the file extension from the input file path.
1063
     *
1064
     * @param string $file
1065
     *  the path of the file to extract the extension of.
1066
     * @return array
1067
     *  an array with a single key 'extension' and a value of the extension
1068
     *  of the input path.
1069
     */
1070
    public static function getExtension($file)
1071
    {
1072
        return pathinfo($file, PATHINFO_EXTENSION);
1073
    }
1074
1075
    /**
1076
     * Gets mime type of a file.
1077
     *
1078
     * For email attachments, the mime type is very important.
1079
     * Uses the PHP 5.3 function `finfo_open` when available, otherwise falls
1080
     * back to using a mapping of known of common mimetypes. If no matches
1081
     * are found `application/octet-stream` will be returned.
1082
     *
1083
     * @author Michael Eichelsdoerfer
1084
     * @author Huib Keemink
1085
     * @param string $file
1086
     * @return string|boolean
1087
     *  the mime type of the file, or false is none found
1088
     */
1089
    public function getMimeType($file)
1090
    {
1091
        if (!empty($file)) {
1092
            // in PHP 5.3 we can use 'finfo'
1093
            if (PHP_VERSION_ID >= 50300 && function_exists('finfo_open')) {
1094
                $finfo = finfo_open(FILEINFO_MIME_TYPE);
1095
                $mime_type = finfo_file($finfo, $file);
1096
                finfo_close($finfo);
1097
            } else {
1098
                // A few mimetypes to "guess" using the file extension.
1099
                $mimetypes = array(
1100
                    'txt'   => 'text/plain',
1101
                    'csv'   => 'text/csv',
1102
                    'pdf'   => 'application/pdf',
1103
                    'doc'   => 'application/msword',
1104
                    'docx'  => 'application/msword',
1105
                    'xls'   => 'application/vnd.ms-excel',
1106
                    'ppt'   => 'application/vnd.ms-powerpoint',
1107
                    'eps'   => 'application/postscript',
1108
                    'zip'   => 'application/zip',
1109
                    'gif'   => 'image/gif',
1110
                    'jpg'   => 'image/jpeg',
1111
                    'jpeg'  => 'image/jpeg',
1112
                    'png'   => 'image/png',
1113
                    'mp3'   => 'audio/mpeg',
1114
                    'mp4a'  => 'audio/mp4',
1115
                    'aac'   => 'audio/x-aac',
1116
                    'aif'   => 'audio/x-aiff',
1117
                    'aiff'  => 'audio/x-aiff',
1118
                    'wav'   => 'audio/x-wav',
1119
                    'wma'   => 'audio/x-ms-wma',
1120
                    'mpeg'  => 'video/mpeg',
1121
                    'mpg'   => 'video/mpeg',
1122
                    'mp4'   => 'video/mp4',
1123
                    'mov'   => 'video/quicktime',
1124
                    'avi'   => 'video/x-msvideo',
1125
                    'wmv'   => 'video/x-ms-wmv',
1126
                );
1127
1128
                $extension = substr(strrchr($file, '.'), 1);
1129
1130
                if ($mimetypes[strtolower($extension)] !== null) {
1131
                    $mime_type = $mimetypes[$extension];
1132
                } else {
1133
                    $mime_type = 'application/octet-stream';
1134
                }
1135
            }
1136
1137
            return $mime_type;
1138
        }
1139
        return false;
1140
    }
1141
1142
    /**
1143
     * Construct a multi-dimensional array that reflects the directory
1144
     * structure of a given path.
1145
     *
1146
     * @param string $dir (optional)
1147
     *  the path of the directory to construct the multi-dimensional array
1148
     *  for. this defaults to '.'.
1149
     * @param string $filter (optional)
1150
     *  A regular expression to filter the directories. This is positive filter, ie.
1151
     * if the filter matches, the directory is included. Defaults to null.
1152
     * @param boolean $recurse (optional)
1153
     *  true if sub-directories should be traversed and reflected in the
1154
     *  resulting array, false otherwise.
1155
     * @param mixed $strip_root (optional)
1156
     *  If null, the full path to the file will be returned, otherwise the value
1157
     *  of `strip_root` will be removed from the file path.
1158
     * @param array $exclude (optional)
1159
     *  ignore directories listed in this array. this defaults to an empty array.
1160
     * @param boolean $ignore_hidden (optional)
1161
     *  ignore hidden directory (i.e.directories that begin with a period). this defaults
1162
     *  to true.
1163
     * @return null|array
1164
     *  return the array structure reflecting the input directory or null if
1165
     * the input directory is not actually a directory.
1166
     */
1167
    public static function listDirStructure($dir = '.', $filter = null, $recurse = true, $strip_root = null, $exclude = array(), $ignore_hidden = true)
1168
    {
1169
        if (!is_dir($dir)) {
1170
            return null;
1171
        }
1172
1173
        $files = array();
1174
1175
        foreach (scandir($dir) as $file) {
1176
            if (
1177
                ($file == '.' || $file == '..')
1178
                || ($ignore_hidden && $file{0} == '.')
1179
                || !is_dir("$dir/$file")
1180
                || in_array($file, $exclude)
1181
                || in_array("$dir/$file", $exclude)
1182
            ) {
1183
                continue;
1184
            }
1185
1186
            if (!is_null($filter)) {
1187
                if (!preg_match($filter, $file)) {
1188
                    continue;
1189
                }
1190
            }
1191
1192
            $files[] = rtrim(str_replace($strip_root, '', $dir), '/') ."/$file/";
1193
1194
            if ($recurse) {
1195
                $files = @array_merge($files, self::listDirStructure("$dir/$file", $filter, $recurse, $strip_root, $exclude, $ignore_hidden));
1196
            }
1197
        }
1198
1199
        return $files;
1200
    }
1201
1202
    /**
1203
     * Construct a multi-dimensional array that reflects the directory
1204
     * structure of a given path grouped into directory and file keys
1205
     * matching any input constraints.
1206
     *
1207
     * @param string $dir (optional)
1208
     *  the path of the directory to construct the multi-dimensional array
1209
     *  for. this defaults to '.'.
1210
     * @param array|string $filters (optional)
1211
     *  either a regular expression to filter the files by or an array of
1212
     *  files to include.
1213
     * @param boolean $recurse (optional)
1214
     *  true if sub-directories should be traversed and reflected in the
1215
     *  resulting array, false otherwise.
1216
     * @param string $sort (optional)
1217
     *  'asc' if the resulting filelist array should be sorted, anything else otherwise.
1218
     *  this defaults to 'asc'.
1219
     * @param mixed $strip_root (optional)
1220
     *  If null, the full path to the file will be returned, otherwise the value
1221
     *  of `strip_root` will be removed from the file path.
1222
     * @param array $exclude (optional)
1223
     *  ignore files listed in this array. this defaults to an empty array.
1224
     * @param boolean $ignore_hidden (optional)
1225
     *  ignore hidden files (i.e. files that begin with a period). this defaults
1226
     *  to true.
1227
     * @return null|array
1228
     *  return the array structure reflecting the input directory or null if
1229
     * the input directory is not actually a directory.
1230
     */
1231
    public static function listStructure($dir = ".", $filters = array(), $recurse = true, $sort = "asc", $strip_root = null, $exclude = array(), $ignore_hidden = true)
1232
    {
1233
        if (!is_dir($dir)) {
1234
            return null;
1235
        }
1236
1237
        // Check to see if $filters is a string containing a regex, or an array of file types
1238
        if (is_array($filters) && !empty($filters)) {
1239
            $filter_type = 'file';
1240
        } elseif (is_string($filters)) {
1241
            $filter_type = 'regex';
1242
        } else {
1243
            $filter_type = null;
1244
        }
1245
        $files = array();
1246
1247
        $prefix = str_replace($strip_root, '', $dir);
1248
1249
        if ($prefix !== "" && substr($prefix, -1) !== "/") {
1250
            $prefix .= "/";
1251
        }
1252
1253
        $files['dirlist'] = array();
1254
        $files['filelist'] = array();
1255
1256
        foreach (scandir($dir) as $file) {
1257
            if (
1258
                ($file == '.' || $file === '..')
1259
                || ($ignore_hidden && $file{0} === '.')
1260
                || in_array($file, $exclude)
1261
                || in_array("$dir/$file", $exclude)
1262
            ) {
1263
                continue;
1264
            }
1265
1266
            $dir = rtrim($dir, '/');
1267
1268
            if (is_dir("$dir/$file")) {
1269
                if ($recurse) {
1270
                    $files["$prefix$file/"] = self::listStructure("$dir/$file", $filters, $recurse, $sort, $strip_root, $exclude, $ignore_hidden);
1271
                }
1272
1273
                $files['dirlist'][] = "$prefix$file/";
1274
            } elseif ($filter_type === 'regex') {
1275
                if (preg_match($filters, $file)) {
1276
                    $files['filelist'][] = "$prefix$file";
1277
                }
1278
            } elseif ($filter_type === 'file') {
1279
                if (in_array(self::getExtension($file), $filters)) {
1280
                    $files['filelist'][] = "$prefix$file";
1281
                }
1282
            } elseif (is_null($filter_type)) {
1283
                $files['filelist'][] = "$prefix$file";
1284
            }
1285
        }
1286
1287
        if (is_array($files['filelist'])) {
1288
            ($sort == 'desc') ? rsort($files['filelist']) : sort($files['filelist']);
1289
        }
1290
1291
        return $files;
1292
    }
1293
1294
    /**
1295
     * Count the number of words in a string. Words are delimited by "spaces".
1296
     * The characters included in the set of "spaces" are:
1297
     *  '&#x2002;', '&#x2003;', '&#x2004;', '&#x2005;',
1298
     *  '&#x2006;', '&#x2007;', '&#x2009;', '&#x200a;',
1299
     *  '&#x200b;', '&#x2002f;', '&#x205f;'
1300
     * Any html/xml tags are first removed by strip_tags() and any included html
1301
     * entities are decoded. The resulting string is then split by the above set
1302
     * of spaces and the resulting size of the resulting array returned.
1303
     *
1304
     * @param string $string
1305
     *  the string from which to count the contained words.
1306
     * @return integer
1307
     *  the number of words contained in the input string.
1308
     */
1309
    public static function countWords($string)
1310
    {
1311
        $string = strip_tags($string);
1312
1313
        // Strip spaces:
1314
        $string = html_entity_decode($string, ENT_NOQUOTES, 'UTF-8');
1315
        $spaces = array(
1316
            '&#x2002;', '&#x2003;', '&#x2004;', '&#x2005;',
1317
            '&#x2006;', '&#x2007;', '&#x2009;', '&#x200a;',
1318
            '&#x200b;', '&#x2002f;', '&#x205f;'
1319
        );
1320
1321
        foreach ($spaces as &$space) {
1322
            $space = html_entity_decode($space, ENT_NOQUOTES, 'UTF-8');
1323
        }
1324
1325
        $string = str_replace($spaces, ' ', $string);
1326
        $string = preg_replace('/[^\w\s]/i', '', $string);
1327
1328
        return str_word_count($string);
1329
    }
1330
1331
    /**
1332
     * Move a file from the source path to the destination path and name and
1333
     * set its permissions to the input permissions. This will ignore errors
1334
     * in the `is_uploaded_file()`, `move_uploaded_file()` and `chmod()` functions.
1335
     *
1336
     * @param string $dest_path
1337
     *  the file path to which the source file is to be moved.
1338
     * @param string #dest_name
1339
     *  the file name within the file path to which the source file is to be moved.
1340
     * @param string $tmp_name
1341
     *  the full path name of the source file to move.
1342
     * @param integer $perm (optional)
1343
     *  the permissions to apply to the moved file. this defaults to 0777.
1344
     * @return boolean
1345
     *  true if the file was moved and its permissions set as required. false otherwise.
1346
     */
1347
    public static function uploadFile($dest_path, $dest_name, $tmp_name, $perm = 0777)
1348
    {
1349
        // Upload the file
1350
        if (@is_uploaded_file($tmp_name)) {
1351
            $dest_path = rtrim($dest_path, '/') . '/';
1352
1353
            // Try place the file in the correction location
1354
            if (@move_uploaded_file($tmp_name, $dest_path . $dest_name)) {
1355
                chmod($dest_path . $dest_name, intval($perm, 8));
1356
                return true;
1357
            }
1358
        }
1359
1360
        // Could not move the file
1361
        return false;
1362
    }
1363
1364
    /**
1365
     * Format a number of bytes in human readable format. This will append MB as
1366
     * appropriate for values greater than 1,024*1,024, KB for values between
1367
     * 1,024 and 1,024*1,024-1 and bytes for values between 0 and 1,024.
1368
     *
1369
     * @param integer $file_size
1370
     *  the number to format.
1371
     * @return string
1372
     *  the formatted number.
1373
     */
1374
    public static function formatFilesize($file_size)
1375
    {
1376
        $file_size = intval($file_size);
1377
1378
        if ($file_size >= (1024 * 1024)) {
1379
            $file_size = number_format($file_size * (1 / (1024 * 1024)), 2) . ' MB';
1380
        } elseif ($file_size >= 1024) {
1381
            $file_size = intval($file_size * (1/1024)) . ' KB';
1382
        } else {
1383
            $file_size = intval($file_size) . ' bytes';
1384
        }
1385
1386
        return $file_size;
1387
    }
1388
1389
    /**
1390
     * Gets the number of bytes from 'human readable' size value. Supports
1391
     * the output of `General::formatFilesize` as well as reading values
1392
     * from the PHP configuration. eg. 1 MB or 1M
1393
     *
1394
     * @since Symphony 2.5.2
1395
     * @param string $file_size
1396
     * @return integer
1397
     */
1398
    public static function convertHumanFileSizeToBytes($file_size)
1399
    {
1400
        $file_size = str_replace(
1401
            array(' MB', ' KB', ' bytes'),
1402
            array('M', 'K', 'B'),
1403
            trim($file_size)
1404
        );
1405
1406
        $last = strtolower($file_size[strlen($file_size)-1]);
1407 View Code Duplication
        switch ($last) {
1408
            case 'g':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1409
                $file_size *= 1024;
1410
            case 'm':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
1411
                $file_size *= 1024;
1412
            case 'k':
1413
                $file_size *= 1024;
1414
        }
1415
1416
        return $file_size;
1417
    }
1418
1419
    /**
1420
     * Construct an XML fragment that reflects the structure of the input timestamp.
1421
     *
1422
     * @param integer $timestamp
1423
     *  the timestamp to construct the XML element from.
1424
     * @param string $element (optional)
1425
     *  the name of the element to append to the namespace of the constructed XML.
1426
     *  this defaults to "date".
1427
     * @param string $date_format (optional)
1428
     *  the format to apply to the date, defaults to `Y-m-d`
1429
     * @param string $time_format (optional)
1430
     *  the format to apply to the date, defaults to `H:i`
1431
     * @param string $namespace (optional)
1432
     *  the namespace in which the resulting XML entity will reside. this defaults
1433
     *  to null.
1434
     * @return boolean|XMLElement
1435
     *  false if there is no XMLElement class on the system, the constructed XML element
1436
     *  otherwise.
1437
     */
1438
    public static function createXMLDateObject($timestamp, $element = 'date', $date_format = 'Y-m-d', $time_format = 'H:i', $namespace = null)
1439
    {
1440
        if (!class_exists('XMLElement')) {
1441
            return false;
1442
        }
1443
1444
        $xDate = new XMLElement(
1445
            (!is_null($namespace) ? $namespace . ':' : '') . $element,
1446
            DateTimeObj::get($date_format, $timestamp),
0 ignored issues
show
Security Bug introduced by
It seems like \DateTimeObj::get($date_format, $timestamp) targeting DateTimeObj::get() can also be of type false; however, XMLElement::__construct() does only seem to accept string|object<XMLElement>|null, did you maybe forget to handle an error condition?
Loading history...
1447
            array(
1448
                'iso' => DateTimeObj::get('c', $timestamp),
1449
                'timestamp' => DateTimeObj::get('U', $timestamp),
1450
                'time' => DateTimeObj::get($time_format, $timestamp),
1451
                'weekday' => DateTimeObj::get('N', $timestamp),
1452
                'offset' => DateTimeObj::get('O', $timestamp)
1453
            )
1454
        );
1455
1456
        return $xDate;
1457
    }
1458
1459
    /**
1460
     * Construct an XML fragment that describes a pagination structure.
1461
     *
1462
     * @param integer $total_entries (optional)
1463
     *  the total number of entries that this structure is paginating. this
1464
     *  defaults to 0.
1465
     * @param integer $total_pages (optional)
1466
     *  the total number of pages within the pagination structure. this defaults
1467
     *  to 0.
1468
     * @param integer $entries_per_page (optional)
1469
     *  the number of entries per page. this defaults to 1.
1470
     * @param integer $current_page (optional)
1471
     *  the current page within the total number of pages within this pagination
1472
     *  structure. this defaults to 1.
1473
     * @return XMLElement
1474
     *  the constructed XML fragment.
1475
     */
1476
    public static function buildPaginationElement($total_entries = 0, $total_pages = 0, $entries_per_page = 1, $current_page = 1)
1477
    {
1478
        $pageinfo = new XMLElement('pagination');
1479
1480
        $pageinfo->setAttribute('total-entries', $total_entries);
1481
        $pageinfo->setAttribute('total-pages', $total_pages);
1482
        $pageinfo->setAttribute('entries-per-page', $entries_per_page);
1483
        $pageinfo->setAttribute('current-page', $current_page);
1484
1485
        return $pageinfo;
1486
    }
1487
1488
    /**
1489
     * Uses `SHA1` or `MD5` to create a hash based on some input
1490
     * This function is currently very basic, but would allow
1491
     * future expansion. Salting the hash comes to mind.
1492
     *
1493
     * @param string $input
1494
     *  the string to be hashed
1495
     * @param string $algorithm
1496
     *  This function supports 'sha1' and 'pbkdf2'. Any
1497
     *  other algorithm will default to 'pbkdf2'.
1498
     * @return string
1499
     *  the hashed string
1500
     */
1501
    public static function hash($input, $algorithm = 'sha1')
1502
    {
1503
        switch ($algorithm) {
1504
            case 'sha1':
1505
                return SHA1::hash($input);
1506
            case 'pbkdf2':
1507
                return PBKDF2::hash($input);
1508
            default:
1509
                return Cryptography::hash($input);
1510
        }
1511
    }
1512
1513
    /**
1514
     * Helper to cut down on variables' type check.
1515
     * Currently known types are the PHP defaults.
1516
     * Uses `is_XXX()` functions internally.
1517
     *
1518
     * @since Symphony 2.3
1519
     *
1520
     * @param array $params - an array of arrays containing variables info
1521
     *
1522
     *  Array[
1523
     *      $key1 => $value1
1524
     *      $key2 => $value2
1525
     *      ...
1526
     *  ]
1527
     *
1528
     *  $key = the name of the variable
1529
     *  $value = Array[
1530
     *      'var' => the variable to check
1531
     *      'type' => enforced type. Must match the XXX part from an `is_XXX()` function
1532
     *      'optional' => boolean. If this is set, the default value of the variable must be null
1533
     *  ]
1534
     *
1535
     * @throws InvalidArgumentException if validator doesn't exist.
1536
     * @throws InvalidArgumentException if variable type validation fails.
1537
     *
1538
     * @example
1539
     *  $color = 'red';
1540
     *  $foo = null;
1541
     *  $bar = 21;
1542
     *
1543
     *  General::ensureType(array(
1544
     *      'color' => array('var' => $color, 'type'=> 'string'),               // success
1545
     *      'foo' => array('var' => $foo, 'type'=> 'int',  'optional' => true), // success
1546
     *      'bar' => array('var' => $bar, 'type'=> 'string')                    // fail
1547
     *  ));
1548
     */
1549
    public static function ensureType(array $params)
1550
    {
1551
        foreach ($params as $name => $param) {
1552
            if (isset($param['optional']) && ($param['optional'] === true)) {
1553
                if (is_null($param['var'])) {
1554
                    continue;
1555
                }
1556
                // if not null, check it's type
1557
            }
1558
1559
            // validate the validator
1560
            $validator = 'is_'.$param['type'];
1561
1562
            if (!function_exists($validator)) {
1563
                throw new InvalidArgumentException(__('Enforced type `%1$s` for argument `$%2$s` does not match any known variable types.', array($param['type'], $name)));
1564
            }
1565
1566
            // validate variable type
1567
            if (!call_user_func($validator, $param['var'])) {
1568
                throw new InvalidArgumentException(__('Argument `$%1$s` is not of type `%2$s`, given `%3$s`.', array($name, $param['type'], gettype($param['var']))));
1569
            }
1570
        }
1571
    }
1572
1573
1574
    /**
1575
     * Wrap a value in CDATA tags for XSL output of non encoded data, only
1576
     * if not already wrapped.
1577
     *
1578
     * @since Symphony 2.3.2
1579
     *
1580
     * @param string $value
1581
     *  The string to wrap in CDATA
1582
     * @return string
1583
     *  The wrapped string
1584
     */
1585
    public static function wrapInCDATA($value)
1586
    {
1587
        if (empty($value)) {
1588
            return $value;
1589
        }
1590
1591
        $startRegExp = '/^' . preg_quote(CDATA_BEGIN) . '/';
1592
        $endRegExp = '/' . preg_quote(CDATA_END) . '$/';
1593
1594
        if (!preg_match($startRegExp, $value)) {
1595
            $value = CDATA_BEGIN . $value;
1596
        }
1597
1598
        if (!preg_match($endRegExp, $value)) {
1599
            $value .= CDATA_END;
1600
        }
1601
1602
        return $value;
1603
    }
1604
1605
    /**
1606
     * Unwrap a value from CDATA tags to return the raw string
1607
     *
1608
     * @since Symphony 2.3.4
1609
     * @param string $value
1610
     *  The string to unwrap from CDATA
1611
     * @return string
1612
     *  The unwrapped string
1613
     */
1614
    public static function unwrapCDATA($value)
1615
    {
1616
        return str_replace(array(CDATA_BEGIN, CDATA_END), '', $value);
1617
    }
1618
1619
    /**
1620
     * Converts a value to a positive integer. This method makes sure that the
1621
     * value is a valid positive integer representation before doing the cast.
1622
     *
1623
     * @since Symphony 2.5
1624
     * @param mixed $value
1625
     *  The value to cast to an integer
1626
     * @return int
1627
     *  The casted integer value if the input is valid, -1 otherwise.
1628
     */
1629
    public static function intval($value)
1630
    {
1631
        if (is_numeric($value) && preg_match('/^[0-9]+$/i', $value) === 1) {
1632
            return intval($value);
1633
        }
1634
1635
        return -1;
1636
    }
1637
1638
    /**
1639
     * Convert a PHP time string like '2 weeks' to seconds
1640
     *
1641
     * @since Symphony 3.0.0
1642
     * @param  string $string
1643
     *  The valid PHP time string
1644
     * @return int
1645
     *  The seconds
1646
     */
1647
    public static function stringToSeconds($string)
1648
    {
1649
        return strtotime($string) - time();
1650
    }
1651
}
1652