Completed
Push — master ( d9f7fe...0d6725 )
by Igor
02:53
created

FileBag::fixPhpFilesArray()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 30
rs 8.5066
c 0
b 0
f 0
cc 7
nc 6
nop 1
1
<?php
2
/**
3
 * @license MIT
4
 */
5
namespace Pivasic\Bundle\Common\File;
6
7
/**
8
 * Class FileBag
9
 * @package Pivasic\Bundle\Common\File
10
 */
11
class FileBag
12
{
13
    /**
14
     * Initialize bag from $_FILES.
15
     *
16
     * @throws \InvalidArgumentException
17
     */
18
    public function __construct()
19
    {
20
        $this->bag = [];
21
22
        foreach ($_FILES as $key => $file) {
23
            if (!is_array($file) && !$file instanceof FileUpload) {
24
                throw new \InvalidArgumentException('An uploaded file must be an array or an instance of FileUpload.');
25
            }
26
            $this->bag[$key] = $this->convertFileInformation($file);
27
        }
28
    }
29
30
    /**
31
     * Returns true if the FILE parameter is defined.
32
     *
33
     * @param string $key
34
     *
35
     * @return bool
36
     */
37
    public function has($key)
38
    {
39
        return array_key_exists($key, $this->bag);
40
    }
41
42
    /**
43
     * An array of parameter names.
44
     *
45
     * @return array
46
     */
47
    public function keys()
48
    {
49
        return array_keys($this->bag);
50
    }
51
52
    /**
53
     * Get value by parameter name.
54
     *
55
     * @param string $key
56
     * @param mixed|null $default The default value if parameter does not exist
57
     *
58
     * @return FileUpload|array|null
59
     */
60
    public function fetch($key, $default = null)
61
    {
62
        return $this->bag[$key] ?? $default;
63
    }
64
65
    /**
66
     * Converts uploaded files to FileUpload instances.
67
     *
68
     * @param array|FileUpload $file A (multi-dimensional) array of uploaded file information
69
     *
70
     * @return array A (multi-dimensional) array of FileUpload instances
71
     */
72
    private function convertFileInformation($file)
73
    {
74
        if ($file instanceof FileUpload) {
75
            return $file;
76
        }
77
78
        $file = $this->fixPhpFilesArray($file);
79
        if (is_array($file)) {
80
            $keys = array_keys($file);
81
            sort($keys);
82
83
            if ($keys == ['error', 'name', 'size', 'tmp_name', 'type']) {
84
                if (UPLOAD_ERR_NO_FILE == $file['error']) {
85
                    $file = null;
86
                } else {
87
                    $file = new FileUpload($file['tmp_name'], $file['name'], $file['size'], $file['type'], $file['error']);
88
                }
89
            } else {
90
                $file = array_map([$this, 'convertFileInformation'], $file);
91
            }
92
        }
93
94
        return $file;
95
    }
96
97
    /**
98
     * Fixes a malformed PHP $_FILES array.
99
     *
100
     * PHP has a bug that the format of the $_FILES array differs, depending on
101
     * whether the uploaded file fields had normal field names or array-like
102
     * field names ("normal" vs. "parent[child]").
103
     *
104
     * This method fixes the array to look like the "normal" $_FILES array.
105
     *
106
     * It's safe to pass an already converted array, in which case this method
107
     * just returns the original array unmodified.
108
     *
109
     * @param array $data
110
     *
111
     * @return array
112
     */
113
    private function fixPhpFilesArray($data)
114
    {
115
        if (!is_array($data)) {
116
            return $data;
117
        }
118
119
        $keys = array_keys($data);
120
        sort($keys);
121
122
        if (['error', 'name', 'size', 'tmp_name', 'type'] != $keys || !isset($data['name']) || !is_array($data['name'])) {
123
            return $data;
124
        }
125
126
        $files = $data;
127
        foreach (['error', 'name', 'size', 'tmp_name', 'type'] as $k) {
128
            unset($files[$k]);
129
        }
130
131
        foreach ($data['name'] as $key => $name) {
132
            $files[$key] = $this->fixPhpFilesArray(array(
133
                'error' => $data['error'][$key],
134
                'name' => $name,
135
                'type' => $data['type'][$key],
136
                'tmp_name' => $data['tmp_name'][$key],
137
                'size' => $data['size'][$key],
138
            ));
139
        }
140
141
        return $files;
142
    }
143
144
    private $bag;
145
}