create_stream()   B
last analyzed

Complexity

Conditions 8
Paths 6

Size

Total Lines 24
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 8

Importance

Changes 0
Metric Value
cc 8
eloc 17
nc 6
nop 2
dl 0
loc 24
ccs 11
cts 11
cp 1
crap 8
rs 8.4444
c 0
b 0
f 0
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, $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
    $type = gettype($resource);
49 2
    if ('resource' === $type) {
50 1
        return new Stream($resource);
51
    }
52
    if ('object' === $type && method_exists($resource, '__toString')) {
53 1
        return create_stream((string)$resource);
54
    }
55 1
    throw new InvalidArgumentException('Failed to create a stream. '
56
        . 'Expected a file name, StreamInterface instance, or a resource. '
57
        . "Given {$type} type.");
58
}
59
60
/**
61
 * Copies the stream to another stream object.
62
 *
63
 * @param StreamInterface $source      The source stream object
64
 * @param StreamInterface $destination Destination stream object
65
 * @param int             [optional] $length Read up to $length bytes from the source stream.
66
 *                                     Fewer than $length bytes may be returned if underlying stream
67
 *                                     call returns fewer bytes
68
 *
69
 * @return int The total count of bytes copied
70
 */
71 1
function stream_copy(
72 1
    StreamInterface $source,
73 1
    StreamInterface $destination,
74
    int $length = 8192): int
75
{
76 1
    $bytes = 0;
77
    while (false === $source->eof()) {
78 1
        $bytes += $destination->write($source->read($length));
79
    }
80
    $destination->close();
81
    return $bytes;
82
}
83
84
/**
85
 * @param StreamInterface $stream
86
 *
87
 * @return string
88
 * @throws \RuntimeException on failure
89 3
 */
90 3
function stream_to_string(StreamInterface $stream): string
91
{
92 3
    $content = '';
93 3
    $stream->rewind();
94
    while (false === $stream->eof()) {
95
        $content .= $stream->read(65536); // 64KB
96 2
    }
97
    return $content;
98
}
99
100
/**
101
 * Transforms the array to much desired files array structure.
102
 * Deals with any nested level.
103
 *
104
 * @param array $files Typically the $_FILES array
105
 *
106
 * @return array A files array to a sane format
107
 */
108
function normalize_files_array(array $files): array
109
{
110 8
    $sane = function(array $files, array $file = [], array $path = []) use (&$sane) {
111 8
        foreach ($files as $k => $v) {
112 8
            $list   = $path;
113
            $list[] = $k;
114 8
            if (is_array($v)) {
115 7
                $file = $sane($v, $file, $list);
116
            } else {
117 8
                $next = array_splice($list, 1, 1);
118 8
                $copy = &$file;
119 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...
120 8
                    $copy = &$copy[$k];
121
                }
122 8
                $copy = $v;
123
            }
124
        }
125
        return $file;
126 8
    };
127 8
    return $sane($files);
128
}
129 8
130
/**
131
 * Preserves the array structure and replaces the
132
 * file description with instance of UploadedFile.
133
 *
134
 * @param array $files Normalized _FILES array
135
 *
136
 * @return array An array tree of UploadedFileInterface instances
137
 */
138
function build_files_array(array $files): array
139
{
140
    foreach ($files as $index => $file) {
141
        if ($file instanceof UploadedFileInterface) {
142 8
            $files[$index] = $file;
143 8
        } elseif (isset($file['tmp_name']) && is_array($file)) {
144 2
            $files[$index] = new UploadedFile($file);
145 7
        } elseif (is_array($file)) {
146 6
            $files[$index] = build_files_array($file);
147 4
        } else {
148 3
            throw new InvalidArgumentException('Failed to process the uploaded files. Invalid file structure provided');
149 3
        }
150
    }
151 1
    return $files;
152
}
153