Completed
Push — master ( 29a6a6...73ebf0 )
by Mihail
15:03
created

create_stream()   B

Complexity

Conditions 8
Paths 6

Size

Total Lines 24
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 8

Importance

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