Passed
Pull Request — master (#17)
by Mihail
15:10
created

functions.php (1 issue)

1
<?php
2
3
namespace Koded\Http;
4
5
/*
6
 * This file is part of the Koded package.
7
 *
8
 * (c) Mihail Binev <[email protected]>
9
 *
10
 * Please view the LICENSE distributed with this source code
11
 * for the full copyright and license information.
12
 *
13
 */
14
15
use InvalidArgumentException;
16
use Psr\Http\Message\{StreamInterface, UploadedFileInterface};
17
use function array_merge;
18
use function array_splice;
19
use function fopen;
20
use function fseek;
21
use function fwrite;
22
use function gettype;
23
use function is_array;
24
use function is_callable;
25
use function is_string;
26
use function method_exists;
27 188
28 161
/**
29 161
 * @param mixed  $resource The string that is to be written
30 161
 * @param string $mode     Type of access to the stream
31
 *
32 161
 * @return StreamInterface
33
 */
34
function create_stream(mixed $resource, string $mode = 'r+b'): StreamInterface
35 28
{
36 3
    if (null === $resource || is_string($resource)) {
37
        $stream = fopen('php://temp', $mode);
38
        fwrite($stream, (string)$resource);
39 25
        fseek($stream, 0);
40 2
        return new Stream($stream);
41
    }
42
    if ($resource instanceof StreamInterface) {
43 23
        return $resource;
44
    }
45 23
    if (is_callable($resource)) {
46 21
        return new CallableStream($resource);
47
    }
48
    if ('resource' === $type = gettype($resource)) {
49 2
        return new Stream($resource);
50 1
    }
51
    if ('object' === $type && method_exists($resource, '__toString')) {
52
        return create_stream((string)$resource);
53 1
    }
54
    throw new InvalidArgumentException('Failed to create a stream. '
55 1
        . 'Expected a file name, StreamInterface instance, or a resource. '
56
        . "Given $type type.");
57
}
58
59
/**
60
 * Copies the stream to another stream object.
61
 *
62
 * @param StreamInterface $source      The source stream object
63
 * @param StreamInterface $destination Destination stream object
64
 * @param int             [optional] $length Read up to $length bytes from the source stream.
65
 *                                     Fewer than $length bytes may be returned if underlying stream
66
 *                                     call returns fewer bytes
67
 *
68
 * @return int The total count of bytes copied
69
 */
70
function stream_copy(
71 1
    StreamInterface $source,
72 1
    StreamInterface $destination,
73 1
    int $length = 8192): int
74
{
75
    $bytes = 0;
76 1
    while (false === $source->eof()) {
77
        $bytes += $destination->write($source->read($length));
78 1
    }
79
    $destination->close();
80
    return $bytes;
81
}
82
83
/**
84
 * @param StreamInterface $stream
85
 *
86
 * @return string
87
 * @throws \RuntimeException on failure
88
 */
89 3
function stream_to_string(StreamInterface $stream): string
90 3
{
91
    $content = '';
92 3
    $stream->rewind();
93 3
    while (false === $stream->eof()) {
94
        $content .= $stream->read(65536); // 64KB
95
    }
96 2
    return $content;
97
}
98
99
/**
100
 * Transforms the array into much desired files array structure.
101
 * Deals with any nested level.
102
 *
103
 * @param array $files Typically the $_FILES array
104
 *
105
 * @return array A files array to a sane format
106
 */
107
function normalize_files_array(array $files): array
108
{
109
    $sane = function(array $files, array $file = [], array $path = []) use (&$sane) {
110 8
        foreach ($files as $k => $v) {
111 8
            $list   = $path;
112 8
            $list[] = $k;
113
            if (is_array($v)) {
114 8
                $file = $sane($v, $file, $list);
115 7
            } else {
116
                $next = array_splice($list, 1, 1);
117 8
                $copy = &$file;
118 8
                foreach (array_merge($list, $next) as $k) {
0 ignored issues
show
Comprehensibility Bug introduced by
$k is overwriting a variable from outer foreach loop.
Loading history...
119 8
                    $copy = &$copy[$k];
120 8
                }
121
                $copy = $v;
122 8
            }
123
        }
124
        return $file;
125
    };
126 8
    return $sane($files);
127 8
}
128
129 8
/**
130
 * Preserves the array structure and replaces the
131
 * file description with instance of UploadedFile.
132
 *
133
 * @param array $files Normalized _FILES array
134
 *
135
 * @return array An array tree of UploadedFileInterface instances
136
 */
137
function build_files_array(array $files): array
138
{
139
    foreach ($files as $index => $file) {
140
        if ($file instanceof UploadedFileInterface) {
141
            $files[$index] = $file;
142 8
        } elseif (isset($file['tmp_name']) && is_array($file)) {
143 8
            $files[$index] = new UploadedFile($file);
144 2
        } elseif (is_array($file)) {
145 7
            $files[$index] = build_files_array($file);
146 6
        } else {
147 4
            throw new InvalidArgumentException('Failed to process the uploaded files. Invalid file structure provided');
148 3
        }
149 3
    }
150
    return $files;
151
}
152