Completed
Branch master (e21175)
by Terry
03:17 queued 01:38
created

UploadedFileHelper::uploadedFileSpecsConvert()   A

Complexity

Conditions 5
Paths 2

Size

Total Lines 32
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 13
c 1
b 0
f 0
dl 0
loc 32
rs 9.5222
cc 5
nc 2
nop 1
1
<?php 
2
/*
3
 * This file is part of the Shieldon package.
4
 *
5
 * (c) Terry L. <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
declare(strict_types=1);
12
13
namespace Shieldon\Psr7\Utils;
14
15
use Shieldon\Psr7\UploadedFile;
16
17
use function array_merge_recursive;
18
use function rtrim;
19
use function is_array;
20
use function is_string;
21
use function is_numeric;
22
23
/*
24
 * The helper functions for converting $_FILES to an array of UploadedFile
25
 * instance, only used on ServerRequest class.
26
 * This class is not a part of PSR 7.
27
 */
28
class UploadedFileHelper
29
{
30
/**
31
     * Create an array for PSR-7 Uploaded File needed.
32
     * 
33
     * @param array $files     An array generally from $_FILES
34
     * @param bool  $isConvert To covert and return $files as an UploadedFile instance.
35
     * 
36
     * @return array|UploadedFile
37
     */
38
    public static function uploadedFileParse(array $files)
39
    {
40
        $specTree = [];
41
42
        $specFields = [
43
            0 => 'tmp_name',
44
            1 => 'name',
45
            2 => 'type',
46
            3 => 'size',
47
            4 => 'error',
48
        ];
49
50
        foreach ($files as $fileKey => $fileValue) {
51
            if (is_string($fileValue['tmp_name']) || is_numeric($fileValue['tmp_name'])) {
52
                $specTree[$fileKey] = $fileValue;
53
54
            } elseif (is_array($fileValue['tmp_name'])) {
55
56
                $tmp = [];
57
58
                // We want to find out how many levels of array it has.
59
                foreach ($specFields as $i => $attr) {
60
                    $tmp[$i] = self::uploadedFileNestedFields($fileValue, $attr);
61
                }
62
63
                $parsedTree = array_merge_recursive(
64
                    $tmp[0], // tmp_name
65
                    $tmp[1], // name
66
                    $tmp[2], // type
67
                    $tmp[3], // size
68
                    $tmp[4]  // error
69
                );
70
  
71
                $specTree[$fileKey] = $parsedTree;
72
                unset($tmp, $parsedTree);
73
            }
74
        }
75
76
        return self::uploadedFileArrayTrim($specTree);
77
    }
78
79
    /**
80
     * Find out how many levels of an array it has.
81
     *
82
     * @param array  $files Data structure from $_FILES.
83
     * @param string $attr  The attributes of a file.
84
     *
85
     * @return array
86
     */
87
    public static function uploadedFileNestedFields(array $files, string $attr): array
88
    {
89
        $result = [];
90
        $values = $files;
91
92
        if (isset($files[$attr])) {
93
            $values = $files[$attr];
94
        }
95
96
        foreach ($values as $key => $value) {
97
98
            /**
99
             * Hereby to add `_` to be a part of the key for letting `array_merge_recursive`
100
             * method can deal with numeric keys as string keys. 
101
             * It will be restored in the next step.
102
             *
103
             * @see uploadedFileArrayTrim
104
             */
105
            if (is_numeric($key)) {
106
                $key .= '_';
107
            }
108
109
            if (is_array($value)) {
110
                $result[$key] = self::uploadedFileNestedFields($value, $attr);
111
            } else {
112
                $result[$key][$attr] = $value;
113
            }
114
        }
115
116
        return $result;
117
    }
118
119
    /**
120
     * That's because that PHP function `array_merge_recursive` has the different
121
     * results as dealing with string keys and numeric keys.
122
     * In the previous step, we made numeric keys to stringify, so that we want to
123
     * restore them back to numeric ones.
124
     *
125
     * @param array|string $values
126
     *
127
     * @return array|string
128
     */
129
    public static function uploadedFileArrayTrim($values)
130
    {
131
        $result = [];
132
133
        if (is_array($values)) {
134
135
            foreach($values as $key => $value) {
136
137
                // Restore the keys back to the original ones.
138
                $key = rtrim($key, '_');
139
140
                if (is_array($value)) {
141
                    $result[$key] = self::uploadedFileArrayTrim($value);
142
                } else {
143
                    $result[$key] = $value;
144
                }
145
            }
146
        }
147
148
        return $result;
149
    }
150
151
    /**
152
     * Convert the parse-ready array into PSR-7 specs.
153
     *
154
     * @param string|array $values
155
     * 
156
     * @return array
157
     */
158
    public static function uploadedFileSpecsConvert($values) 
159
    {
160
        $result = [];
161
162
        if (is_array($values)) {
163
164
            foreach ($values as $key => $value) {
165
166
                if (is_array($value)) {
167
168
                    // Continue querying self, until a string is found.
169
                    $result[$key] = self::uploadedFileSpecsConvert($value);
170
171
                } elseif ($key === 'tmp_name') {
172
173
                    /**
174
                     * Once one of the keys on the same level has been found,
175
                     * then we can fetch the others at a time.
176
                     * In this case, the `tmp_name` found.
177
                     */
178
                    $result = new uploadedFile(
179
                        $values['tmp_name'],
180
                        $values['name'],
181
                        $values['type'],
182
                        $values['size'],
183
                        $values['error']
184
                    );
185
                }
186
            }
187
        }
188
189
        return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result also could return the type Shieldon\Psr7\UploadedFile which is incompatible with the documented return type array.
Loading history...
190
    }
191
}