FileBag   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 131
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 1
dl 0
loc 131
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 4
A has() 0 4 1
A keys() 0 4 1
A fetch() 0 4 1
A convertFileInformation() 0 24 5
B fixPhpFilesArray() 0 30 7
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
     * @return bool
35
     */
36
    public function has(string $key): bool
37
    {
38
        return array_key_exists($key, $this->bag);
39
    }
40
41
    /**
42
     * An array of parameter names.
43
     *
44
     * @return array
45
     */
46
    public function keys(): array
47
    {
48
        return array_keys($this->bag);
49
    }
50
51
    /**
52
     * Get value by parameter name.
53
     *
54
     * @param string $key
55
     * @param mixed|null $default The default value if parameter does not exist
56
     * @return FileUpload|array|null
57
     */
58
    public function fetch(string $key, $default = null)
59
    {
60
        return $this->bag[$key] ?? $default;
61
    }
62
63
    /**
64
     * Converts uploaded files to FileUpload instances.
65
     *
66
     * @param array|FileUpload $file A (multi-dimensional) array of uploaded file information
67
     * @return array A (multi-dimensional) array of FileUpload instances
68
     */
69
    private function convertFileInformation($file)
70
    {
71
        if ($file instanceof FileUpload) {
72
            return $file;
73
        }
74
75
        $file = $this->fixPhpFilesArray($file);
76
        if (is_array($file)) {
77
            $keys = array_keys($file);
78
            sort($keys);
79
80
            if ($keys == ['error', 'name', 'size', 'tmp_name', 'type']) {
81
                if (UPLOAD_ERR_NO_FILE == $file['error']) {
82
                    $file = null;
83
                } else {
84
                    $file = new FileUpload($file['tmp_name'], $file['name'], $file['size'], $file['type'], $file['error']);
85
                }
86
            } else {
87
                $file = array_map([$this, 'convertFileInformation'], $file);
88
            }
89
        }
90
91
        return $file;
92
    }
93
94
    /**
95
     * Fixes a malformed PHP $_FILES array.
96
     *
97
     * PHP has a bug that the format of the $_FILES array differs, depending on
98
     * whether the uploaded file fields had normal field names or array-like
99
     * field names ("normal" vs. "parent[child]").
100
     *
101
     * This method fixes the array to look like the "normal" $_FILES array.
102
     *
103
     * It's safe to pass an already converted array, in which case this method
104
     * just returns the original array unmodified.
105
     *
106
     * @param array $data
107
     * @return array
108
     */
109
    private function fixPhpFilesArray(array $data): array
110
    {
111
        if (!is_array($data)) {
112
            return $data;
113
        }
114
115
        $keys = array_keys($data);
116
        sort($keys);
117
118
        if (['error', 'name', 'size', 'tmp_name', 'type'] != $keys || !isset($data['name']) || !is_array($data['name'])) {
119
            return $data;
120
        }
121
122
        $files = $data;
123
        foreach (['error', 'name', 'size', 'tmp_name', 'type'] as $k) {
124
            unset($files[$k]);
125
        }
126
127
        foreach ($data['name'] as $key => $name) {
128
            $files[$key] = $this->fixPhpFilesArray(array(
129
                'error' => $data['error'][$key],
130
                'name' => $name,
131
                'type' => $data['type'][$key],
132
                'tmp_name' => $data['tmp_name'][$key],
133
                'size' => $data['size'][$key],
134
            ));
135
        }
136
137
        return $files;
138
    }
139
140
    private $bag;
141
}