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
Push — integration ( 02db51...9a9ecd )
by Brendan
06:02
created

class.general.php ➔ merge_file_post_data()   A

Complexity

Conditions 4

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 4
dl 0
loc 14
rs 9.2
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) {
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 $length
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
     * @param string $file
1017
     * @return boolean
1018
     */
1019
    public static function checkFile($file)
1020
    {
1021
        clearstatcache();
1022
        $dir = dirname($file);
1023
1024
        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...
1025
            (!is_writable($dir) || !is_readable($dir)) // Folder
1026
            || (file_exists($file) && (!is_readable($file) || !is_writable($file))) // File
1027
        ) {
1028
            return false;
1029
        }
1030
1031
        return true;
1032
    }
1033
1034
    /**
1035
     * Delete a file at a given path, silently ignoring errors depending
1036
     * on the value of the input variable $silent.
1037
     *
1038
     * @param string $file
1039
     *  the path of the file to delete
1040
     * @param boolean $silent (optional)
1041
     *  true if an exception should be raised if an error occurs, false
1042
     *  otherwise. this defaults to true.
1043
     * @throws Exception
1044
     * @return boolean
1045
     *  true if the file is successfully unlinked, if the unlink fails and
1046
     *  silent is set to true then an exception is thrown. if the unlink
1047
     *  fails and silent is set to false then this returns false.
1048
     */
1049
    public static function deleteFile($file, $silent = true)
1050
    {
1051
        try {
1052
            return unlink($file);
1053
        } catch (Exception $ex) {
1054
            if ($silent === false) {
1055
                throw new Exception(__('Unable to remove file - %s', array($file)));
1056
            }
1057
1058
            return false;
1059
        }
1060
    }
1061
1062
    /**
1063
     * Extract the file extension from the input file path.
1064
     *
1065
     * @param string $file
1066
     *  the path of the file to extract the extension of.
1067
     * @return array
1068
     *  an array with a single key 'extension' and a value of the extension
1069
     *  of the input path.
1070
     */
1071
    public static function getExtension($file)
1072
    {
1073
        return pathinfo($file, PATHINFO_EXTENSION);
1074
    }
1075
1076
    /**
1077
     * Gets mime type of a file.
1078
     *
1079
     * For email attachments, the mime type is very important.
1080
     * Uses the PHP 5.3 function `finfo_open` when available, otherwise falls
1081
     * back to using a mapping of known of common mimetypes. If no matches
1082
     * are found `application/octet-stream` will be returned.
1083
     *
1084
     * @author Michael Eichelsdoerfer
1085
     * @author Huib Keemink
1086
     * @param string $file
1087
     * @return string|boolean
1088
     *  the mime type of the file, or false is none found
1089
     */
1090
    public function getMimeType($file)
1091
    {
1092
        if (!empty($file)) {
1093
            // in PHP 5.3 we can use 'finfo'
1094
            if (PHP_VERSION_ID >= 50300 && function_exists('finfo_open')) {
1095
                $finfo = finfo_open(FILEINFO_MIME_TYPE);
1096
                $mime_type = finfo_file($finfo, $file);
1097
                finfo_close($finfo);
1098
            } else {
1099
                // A few mimetypes to "guess" using the file extension.
1100
                $mimetypes = array(
1101
                    'txt'   => 'text/plain',
1102
                    'csv'   => 'text/csv',
1103
                    'pdf'   => 'application/pdf',
1104
                    'doc'   => 'application/msword',
1105
                    'docx'  => 'application/msword',
1106
                    'xls'   => 'application/vnd.ms-excel',
1107
                    'ppt'   => 'application/vnd.ms-powerpoint',
1108
                    'eps'   => 'application/postscript',
1109
                    'zip'   => 'application/zip',
1110
                    'gif'   => 'image/gif',
1111
                    'jpg'   => 'image/jpeg',
1112
                    'jpeg'  => 'image/jpeg',
1113
                    'png'   => 'image/png',
1114
                    'mp3'   => 'audio/mpeg',
1115
                    'mp4a'  => 'audio/mp4',
1116
                    'aac'   => 'audio/x-aac',
1117
                    'aif'   => 'audio/x-aiff',
1118
                    'aiff'  => 'audio/x-aiff',
1119
                    'wav'   => 'audio/x-wav',
1120
                    'wma'   => 'audio/x-ms-wma',
1121
                    'mpeg'  => 'video/mpeg',
1122
                    'mpg'   => 'video/mpeg',
1123
                    'mp4'   => 'video/mp4',
1124
                    'mov'   => 'video/quicktime',
1125
                    'avi'   => 'video/x-msvideo',
1126
                    'wmv'   => 'video/x-ms-wmv',
1127
                );
1128
1129
                $extension = substr(strrchr($file, '.'), 1);
1130
1131
                if ($mimetypes[strtolower($extension)] !== null) {
1132
                    $mime_type = $mimetypes[$extension];
1133
                } else {
1134
                    $mime_type = 'application/octet-stream';
1135
                }
1136
            }
1137
1138
            return $mime_type;
1139
        }
1140
        return false;
1141
    }
1142
1143
    /**
1144
     * Construct a multi-dimensional array that reflects the directory
1145
     * structure of a given path.
1146
     *
1147
     * @param string $dir (optional)
1148
     *  the path of the directory to construct the multi-dimensional array
1149
     *  for. this defaults to '.'.
1150
     * @param string $filter (optional)
1151
     *  A regular expression to filter the directories. This is positive filter, ie.
1152
     * if the filter matches, the directory is included. Defaults to null.
1153
     * @param boolean $recurse (optional)
1154
     *  true if sub-directories should be traversed and reflected in the
1155
     *  resulting array, false otherwise.
1156
     * @param mixed $strip_root (optional)
1157
     *  If null, the full path to the file will be returned, otherwise the value
1158
     *  of `strip_root` will be removed from the file path.
1159
     * @param array $exclude (optional)
1160
     *  ignore directories listed in this array. this defaults to an empty array.
1161
     * @param boolean $ignore_hidden (optional)
1162
     *  ignore hidden directory (i.e.directories that begin with a period). this defaults
1163
     *  to true.
1164
     * @return null|array
1165
     *  return the array structure reflecting the input directory or null if
1166
     * the input directory is not actually a directory.
1167
     */
1168
    public static function listDirStructure($dir = '.', $filter = null, $recurse = true, $strip_root = null, $exclude = array(), $ignore_hidden = true)
1169
    {
1170
        if (!is_dir($dir)) {
1171
            return null;
1172
        }
1173
1174
        $files = array();
1175
1176
        foreach (scandir($dir) as $file) {
1177 View Code Duplication
            if (
1178
                ($file === '.' || $file === '..')
1179
                || ($ignore_hidden && $file{0} === '.')
1180
                || !is_dir("$dir/$file")
1181
                || in_array($file, $exclude)
1182
                || in_array("$dir/$file", $exclude)
1183
            ) {
1184
                continue;
1185
            }
1186
1187
            if (!is_null($filter)) {
1188
                if (!preg_match($filter, $file)) {
1189
                    continue;
1190
                }
1191
            }
1192
1193
            $files[] = rtrim(str_replace($strip_root, '', $dir), '/') ."/$file/";
1194
1195
            if ($recurse) {
1196
                $files = @array_merge($files, self::listDirStructure("$dir/$file", $filter, $recurse, $strip_root, $exclude, $ignore_hidden));
1197
            }
1198
        }
1199
1200
        return $files;
1201
    }
1202
1203
    /**
1204
     * Construct a multi-dimensional array that reflects the directory
1205
     * structure of a given path grouped into directory and file keys
1206
     * matching any input constraints.
1207
     *
1208
     * @param string $dir (optional)
1209
     *  the path of the directory to construct the multi-dimensional array
1210
     *  for. this defaults to '.'.
1211
     * @param array|string $filters (optional)
1212
     *  either a regular expression to filter the files by or an array of
1213
     *  files to include.
1214
     * @param boolean $recurse (optional)
1215
     *  true if sub-directories should be traversed and reflected in the
1216
     *  resulting array, false otherwise.
1217
     * @param string $sort (optional)
1218
     *  'asc' if the resulting filelist array should be sorted, anything else otherwise.
1219
     *  this defaults to 'asc'.
1220
     * @param mixed $strip_root (optional)
1221
     *  If null, the full path to the file will be returned, otherwise the value
1222
     *  of `strip_root` will be removed from the file path.
1223
     * @param array $exclude (optional)
1224
     *  ignore files listed in this array. this defaults to an empty array.
1225
     * @param boolean $ignore_hidden (optional)
1226
     *  ignore hidden files (i.e. files that begin with a period). this defaults
1227
     *  to true.
1228
     * @return null|array
1229
     *  return the array structure reflecting the input directory or null if
1230
     * the input directory is not actually a directory.
1231
     */
1232
    public static function listStructure($dir = ".", $filters = array(), $recurse = true, $sort = "asc", $strip_root = null, $exclude = array(), $ignore_hidden = true)
1233
    {
1234
        if (!is_dir($dir)) {
1235
            return null;
1236
        }
1237
1238
        // Check to see if $filters is a string containing a regex, or an array of file types
1239
        if (is_array($filters) && !empty($filters)) {
1240
            $filter_type = 'file';
1241
        } elseif (is_string($filters)) {
1242
            $filter_type = 'regex';
1243
        } else {
1244
            $filter_type = null;
1245
        }
1246
        $files = array();
1247
1248
        $prefix = str_replace($strip_root, '', $dir);
1249
1250
        if ($prefix !== "" && substr($prefix, -1) !== "/") {
1251
            $prefix .= "/";
1252
        }
1253
1254
        $files['dirlist'] = array();
1255
        $files['filelist'] = array();
1256
1257
        foreach (scandir($dir) as $file) {
1258 View Code Duplication
            if (
1259
                ($file === '.' || $file === '..')
1260
                || ($ignore_hidden && $file{0} === '.')
1261
                || in_array($file, $exclude)
1262
                || in_array("$dir/$file", $exclude)
1263
            ) {
1264
                continue;
1265
            }
1266
1267
            $dir = rtrim($dir, '/');
1268
1269
            if (is_dir("$dir/$file")) {
1270
                if ($recurse) {
1271
                    $files["$prefix$file/"] = self::listStructure("$dir/$file", $filters, $recurse, $sort, $strip_root, $exclude, $ignore_hidden);
1272
                }
1273
1274
                $files['dirlist'][] = "$prefix$file/";
1275
            } elseif ($filter_type === 'regex') {
1276
                if (preg_match($filters, $file)) {
1277
                    $files['filelist'][] = "$prefix$file";
1278
                }
1279
            } elseif ($filter_type === 'file') {
1280
                if (in_array(self::getExtension($file), $filters)) {
1281
                    $files['filelist'][] = "$prefix$file";
1282
                }
1283
            } elseif (is_null($filter_type)) {
1284
                $files['filelist'][] = "$prefix$file";
1285
            }
1286
        }
1287
1288
        if (is_array($files['filelist'])) {
1289
            ($sort === 'desc') ? rsort($files['filelist']) : sort($files['filelist']);
1290
        }
1291
1292
        return $files;
1293
    }
1294
1295
    /**
1296
     * Count the number of words in a string. Words are delimited by "spaces".
1297
     * The characters included in the set of "spaces" are:
1298
     *  '&#x2002;', '&#x2003;', '&#x2004;', '&#x2005;',
1299
     *  '&#x2006;', '&#x2007;', '&#x2009;', '&#x200a;',
1300
     *  '&#x200b;', '&#x2002f;', '&#x205f;'
1301
     * Any html/xml tags are first removed by strip_tags() and any included html
1302
     * entities are decoded. The resulting string is then split by the above set
1303
     * of spaces and the resulting size of the resulting array returned.
1304
     *
1305
     * @param string $string
1306
     *  the string from which to count the contained words.
1307
     * @return integer
1308
     *  the number of words contained in the input string.
1309
     */
1310
    public static function countWords($string)
1311
    {
1312
        $string = strip_tags($string);
1313
1314
        // Strip spaces:
1315
        $string = html_entity_decode($string, ENT_NOQUOTES, 'UTF-8');
1316
        $spaces = array(
1317
            '&#x2002;', '&#x2003;', '&#x2004;', '&#x2005;',
1318
            '&#x2006;', '&#x2007;', '&#x2009;', '&#x200a;',
1319
            '&#x200b;', '&#x2002f;', '&#x205f;'
1320
        );
1321
1322
        foreach ($spaces as &$space) {
1323
            $space = html_entity_decode($space, ENT_NOQUOTES, 'UTF-8');
1324
        }
1325
1326
        $string = str_replace($spaces, ' ', $string);
1327
        $string = preg_replace('/[^\w\s]/i', '', $string);
1328
1329
        return str_word_count($string);
1330
    }
1331
1332
    /**
1333
     * Move a file from the source path to the destination path and name and
1334
     * set its permissions to the input permissions. This will ignore errors
1335
     * in the `is_uploaded_file()`, `move_uploaded_file()` and `chmod()` functions.
1336
     *
1337
     * @param string $dest_path
1338
     *  the file path to which the source file is to be moved.
1339
     * @param string #dest_name
1340
     *  the file name within the file path to which the source file is to be moved.
1341
     * @param string $tmp_name
1342
     *  the full path name of the source file to move.
1343
     * @param integer $perm (optional)
1344
     *  the permissions to apply to the moved file. this defaults to 0777.
1345
     * @return boolean
1346
     *  true if the file was moved and its permissions set as required. false otherwise.
1347
     */
1348
    public static function uploadFile($dest_path, $dest_name, $tmp_name, $perm = 0777)
1349
    {
1350
        // Upload the file
1351
        if (@is_uploaded_file($tmp_name)) {
1352
            $dest_path = rtrim($dest_path, '/') . '/';
1353
1354
            // Try place the file in the correction location
1355
            if (@move_uploaded_file($tmp_name, $dest_path . $dest_name)) {
1356
                chmod($dest_path . $dest_name, intval($perm, 8));
1357
                return true;
1358
            }
1359
        }
1360
1361
        // Could not move the file
1362
        return false;
1363
    }
1364
1365
    /**
1366
     * Format a number of bytes in human readable format. This will append MB as
1367
     * appropriate for values greater than 1,024*1,024, KB for values between
1368
     * 1,024 and 1,024*1,024-1 and bytes for values between 0 and 1,024.
1369
     *
1370
     * @param integer $file_size
1371
     *  the number to format.
1372
     * @return string
1373
     *  the formatted number.
1374
     */
1375
    public static function formatFilesize($file_size)
1376
    {
1377
        $file_size = intval($file_size);
1378
1379
        if ($file_size >= (1024 * 1024)) {
1380
            $file_size = number_format($file_size * (1 / (1024 * 1024)), 2) . ' MB';
1381
        } elseif ($file_size >= 1024) {
1382
            $file_size = intval($file_size * (1/1024)) . ' KB';
1383
        } else {
1384
            $file_size = intval($file_size) . ' bytes';
1385
        }
1386
1387
        return $file_size;
1388
    }
1389
1390
    /**
1391
     * Gets the number of bytes from 'human readable' size value. Supports
1392
     * the output of `General::formatFilesize` as well as reading values
1393
     * from the PHP configuration. eg. 1 MB or 1M
1394
     *
1395
     * @since Symphony 2.5.2
1396
     * @param string $file_size
1397
     * @return integer
1398
     */
1399
    public static function convertHumanFileSizeToBytes($file_size)
1400
    {
1401
        $file_size = str_replace(
1402
            array(' MB', ' KB', ' bytes'),
1403
            array('M', 'K', 'B'),
1404
            trim($file_size)
1405
        );
1406
1407
        $last = strtolower($file_size[strlen($file_size)-1]);
1408 View Code Duplication
        switch ($last) {
1409
            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...
1410
                $file_size *= 1024;
1411
            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...
1412
                $file_size *= 1024;
1413
            case 'k':
1414
                $file_size *= 1024;
1415
        }
1416
1417
        return $file_size;
1418
    }
1419
1420
    /**
1421
     * Construct an XML fragment that reflects the structure of the input timestamp.
1422
     *
1423
     * @param integer $timestamp
1424
     *  the timestamp to construct the XML element from.
1425
     * @param string $element (optional)
1426
     *  the name of the element to append to the namespace of the constructed XML.
1427
     *  this defaults to "date".
1428
     * @param string $date_format (optional)
1429
     *  the format to apply to the date, defaults to `Y-m-d`
1430
     * @param string $time_format (optional)
1431
     *  the format to apply to the date, defaults to `H:i`
1432
     * @param string $namespace (optional)
1433
     *  the namespace in which the resulting XML entity will reside. this defaults
1434
     *  to null.
1435
     * @return boolean|XMLElement
1436
     *  false if there is no XMLElement class on the system, the constructed XML element
1437
     *  otherwise.
1438
     */
1439
    public static function createXMLDateObject($timestamp, $element = 'date', $date_format = 'Y-m-d', $time_format = 'H:i', $namespace = null)
1440
    {
1441
        if (!class_exists('XMLElement')) {
1442
            return false;
1443
        }
1444
1445
        $xDate = new XMLElement(
1446
            (!is_null($namespace) ? $namespace . ':' : '') . $element,
1447
            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...
1448
            array(
1449
                'iso' => DateTimeObj::get('c', $timestamp),
1450
                'timestamp' => DateTimeObj::get('U', $timestamp),
1451
                'time' => DateTimeObj::get($time_format, $timestamp),
1452
                'weekday' => DateTimeObj::get('N', $timestamp),
1453
                'offset' => DateTimeObj::get('O', $timestamp)
1454
            )
1455
        );
1456
1457
        return $xDate;
1458
    }
1459
1460
    /**
1461
     * Construct an XML fragment that describes a pagination structure.
1462
     *
1463
     * @param integer $total_entries (optional)
1464
     *  the total number of entries that this structure is paginating. this
1465
     *  defaults to 0.
1466
     * @param integer $total_pages (optional)
1467
     *  the total number of pages within the pagination structure. this defaults
1468
     *  to 0.
1469
     * @param integer $entries_per_page (optional)
1470
     *  the number of entries per page. this defaults to 1.
1471
     * @param integer $current_page (optional)
1472
     *  the current page within the total number of pages within this pagination
1473
     *  structure. this defaults to 1.
1474
     * @return XMLElement
1475
     *  the constructed XML fragment.
1476
     */
1477
    public static function buildPaginationElement($total_entries = 0, $total_pages = 0, $entries_per_page = 1, $current_page = 1)
1478
    {
1479
        $pageinfo = new XMLElement('pagination');
1480
1481
        $pageinfo->setAttribute('total-entries', $total_entries);
1482
        $pageinfo->setAttribute('total-pages', $total_pages);
1483
        $pageinfo->setAttribute('entries-per-page', $entries_per_page);
1484
        $pageinfo->setAttribute('current-page', $current_page);
1485
1486
        return $pageinfo;
1487
    }
1488
1489
    /**
1490
     * Uses `SHA1` or `MD5` to create a hash based on some input
1491
     * This function is currently very basic, but would allow
1492
     * future expansion. Salting the hash comes to mind.
1493
     *
1494
     * @param string $input
1495
     *  the string to be hashed
1496
     * @param string $algorithm
1497
     *  This function supports 'sha1' and 'pbkdf2'. Any
1498
     *  other algorithm will default to 'pbkdf2'.
1499
     * @return string
1500
     *  the hashed string
1501
     */
1502
    public static function hash($input, $algorithm = 'sha1')
1503
    {
1504
        switch ($algorithm) {
1505
            case 'sha1':
1506
                return SHA1::hash($input);
1507
            case 'pbkdf2':
1508
                return PBKDF2::hash($input);
1509
            default:
1510
                return Cryptography::hash($input);
1511
        }
1512
    }
1513
1514
    /**
1515
     * Helper to cut down on variables' type check.
1516
     * Currently known types are the PHP defaults.
1517
     * Uses `is_XXX()` functions internally.
1518
     *
1519
     * @since Symphony 2.3
1520
     *
1521
     * @param array $params - an array of arrays containing variables info
1522
     *
1523
     *  Array[
1524
     *      $key1 => $value1
1525
     *      $key2 => $value2
1526
     *      ...
1527
     *  ]
1528
     *
1529
     *  $key = the name of the variable
1530
     *  $value = Array[
1531
     *      'var' => the variable to check
1532
     *      'type' => enforced type. Must match the XXX part from an `is_XXX()` function
1533
     *      'optional' => boolean. If this is set, the default value of the variable must be null
1534
     *  ]
1535
     *
1536
     * @throws InvalidArgumentException if validator doesn't exist.
1537
     * @throws InvalidArgumentException if variable type validation fails.
1538
     *
1539
     * @example
1540
     *  $color = 'red';
1541
     *  $foo = null;
1542
     *  $bar = 21;
1543
     *
1544
     *  General::ensureType(array(
1545
     *      'color' => array('var' => $color, 'type'=> 'string'),               // success
1546
     *      'foo' => array('var' => $foo, 'type'=> 'int',  'optional' => true), // success
1547
     *      'bar' => array('var' => $bar, 'type'=> 'string')                    // fail
1548
     *  ));
1549
     */
1550
    public static function ensureType(array $params)
1551
    {
1552
        foreach ($params as $name => $param) {
1553
            if (isset($param['optional']) && ($param['optional'] === true)) {
1554
                if (is_null($param['var'])) {
1555
                    continue;
1556
                }
1557
                // if not null, check it's type
1558
            }
1559
1560
            // validate the validator
1561
            $validator = 'is_'.$param['type'];
1562
1563
            if (!function_exists($validator)) {
1564
                throw new InvalidArgumentException(__('Enforced type `%1$s` for argument `$%2$s` does not match any known variable types.', array($param['type'], $name)));
1565
            }
1566
1567
            // validate variable type
1568
            if (!call_user_func($validator, $param['var'])) {
1569
                throw new InvalidArgumentException(__('Argument `$%1$s` is not of type `%2$s`, given `%3$s`.', array($name, $param['type'], gettype($param['var']))));
1570
            }
1571
        }
1572
    }
1573
1574
1575
    /**
1576
     * Wrap a value in CDATA tags for XSL output of non encoded data, only
1577
     * if not already wrapped.
1578
     *
1579
     * @since Symphony 2.3.2
1580
     *
1581
     * @param string $value
1582
     *  The string to wrap in CDATA
1583
     * @return string
1584
     *  The wrapped string
1585
     */
1586
    public static function wrapInCDATA($value)
1587
    {
1588
        if (empty($value)) {
1589
            return $value;
1590
        }
1591
1592
        $startRegExp = '/^' . preg_quote(CDATA_BEGIN) . '/';
1593
        $endRegExp = '/' . preg_quote(CDATA_END) . '$/';
1594
1595
        if (!preg_match($startRegExp, $value)) {
1596
            $value = CDATA_BEGIN . $value;
1597
        }
1598
1599
        if (!preg_match($endRegExp, $value)) {
1600
            $value .= CDATA_END;
1601
        }
1602
1603
        return $value;
1604
    }
1605
1606
    /**
1607
     * Unwrap a value from CDATA tags to return the raw string
1608
     *
1609
     * @since Symphony 2.3.4
1610
     * @param string $value
1611
     *  The string to unwrap from CDATA
1612
     * @return string
1613
     *  The unwrapped string
1614
     */
1615
    public static function unwrapCDATA($value)
1616
    {
1617
        return str_replace(array(CDATA_BEGIN, CDATA_END), '', $value);
1618
    }
1619
1620
    /**
1621
     * Converts a value to a positive integer. This method makes sure that the
1622
     * value is a valid positive integer representation before doing the cast.
1623
     *
1624
     * @since Symphony 2.5
1625
     * @param mixed $value
1626
     *  The value to cast to an integer
1627
     * @return int
1628
     *  The casted integer value if the input is valid, -1 otherwise.
1629
     */
1630
    public static function intval($value)
1631
    {
1632
        if (is_numeric($value) && preg_match('/^[0-9]+$/i', $value) === 1) {
1633
            return intval($value);
1634
        }
1635
1636
        return -1;
1637
    }
1638
1639
    /**
1640
     * Convert a PHP time string like '2 weeks' to seconds
1641
     *
1642
     * @since Symphony 3.0.0
1643
     * @param  string $string
1644
     *  The valid PHP time string
1645
     * @return int
1646
     *  The seconds
1647
     */
1648
    public static function stringToSeconds($string)
1649
    {
1650
        return strtotime($string) - time();
1651
    }
1652
}
1653