UploadedFilesFactory::saneFilesArray()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 11
c 2
b 0
f 0
dl 0
loc 19
rs 9.9
cc 4
nc 4
nop 1
1
<?php
2
3
/**
4
 * This file is part of Http
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace Slick\Http\Message\Server;
11
12
/**
13
 * UploadedFilesFactory
14
 *
15
 * @package Slick\Http\Message\Server
16
 */
17
class UploadedFilesFactory
18
{
19
20
    /**
21
     * Creates the uploaded file objects within a normalized files tree
22
     *
23
     * @return array|UploadedFile[]
24
     */
25
    public static function createFiles()
26
    {
27
        $fixer = new static();
28
        $files = $fixer->saneFilesArray($_FILES);
29
        $fixed = [];
30
        foreach ($files as $key => $data) {
31
            $fixed[$key] = $fixer->createUploadedFile($data);
32
        }
33
        return $fixed;
34
    }
35
36
    /**
37
     * Helper function to recursively create UploadedFile objects
38
     *
39
     * @param array $data
40
     *
41
     * @return array|UploadedFile
42
     */
43
    private function createUploadedFile($data)
44
    {
45
        if (array_key_exists('tmp_name', $data)) {
46
            return UploadedFile::create($data);
47
        }
48
49
        $result = [];
50
        foreach ($data as $key => $datum) {
51
            $result[$key] = $this->createUploadedFile($datum);
52
        }
53
        return $result;
54
    }
55
56
    /**
57
     * Fixes the $_FILES array structure
58
     *
59
     * For each subtree in the file tree that's more than one item deep:
60
     *      For each leaf of the subtree:
61
     *      $leaf[a][b][c] ... [y][z] -> $result[z][a][b][c]  ... [y]
62
     *
63
     *
64
     * @see: https://stackoverflow.com/a/24397828/1271488
65
     *
66
     * @param array $files
67
     * @return array
68
     */
69
    private function saneFilesArray(array $files)
70
    {
71
        $result = [];
72
73
        foreach ($files as $field => $data) {
74
            foreach ($data as $key => $val) {
75
                $result[$field] = [];
76
                if (!is_array($val)) {
77
                    $result[$field] = $data;
78
                    continue;
79
                }
80
81
                $res = [];
82
                $this->filesFlip($res, [], $data);
83
                $result[$field] += $res;
84
            }
85
        }
86
87
        return $result;
88
    }
89
90
    /**
91
     * Move the innermost key to the outer spot
92
     *
93
     * @param array  $result
94
     * @param array  $keys
95
     * @param mixed  $value
96
     */
97
    private function filesFlip(&$result, $keys, $value)
98
    {
99
        if (is_array($value)) {
100
            foreach ($value as $k => $v) {
101
                $newKeys = $keys;
102
                array_push($newKeys, $k);
103
                $this->filesFlip($result, $newKeys, $v);
104
            }
105
            return;
106
        }
107
108
        $res = $value;
109
        // Move the innermost key to the outer spot
110
        $first = array_shift($keys);
111
        array_push($keys, $first);
112
        foreach (array_reverse($keys) as $kk) {
113
            // You might think we'd say $res[$kk] = $res, but $res starts
114
            // out not as an array
115
            $res = array($kk => $res);
116
        }
117
118
        $result = $this->arrayMergeRecursive($result, $res);
119
    }
120
121
    /**
122
     * Recursively merge provided arrays
123
     *
124
     * @param array|string $array1
125
     * @param array|string $array2
126
     *
127
     * @return array
128
     */
129
    private function arrayMergeRecursive($array1, $array2)
130
    {
131
        if (!is_array($array1) or !is_array($array2)) {
132
            return $array2;
133
        }
134
135
        foreach ($array2 as $sKey2 => $sValue2) {
136
            $array1[$sKey2] = $this->arrayMergeRecursive(@$array1[$sKey2], $sValue2);
137
        }
138
        return $array1;
139
    }
140
}
141