Completed
Push — master ( 3e15a8...ec1159 )
by Mihail
09:16
created

functions.php (4 issues)

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 RuntimeException;
18
19
/**
20
 * @param null|callable|StreamInterface|object|resource $resource A gypsy wannabe argument
21
 * @param string                                        $mode
22
 *
23
 * @return StreamInterface
24
 */
25
function create_stream($resource, string $mode = 'r+'): StreamInterface
26
{
27
    if (null === $resource || is_string($resource)) {
28
        $stream = fopen('php://temp', $mode);
29
        fwrite($stream, $resource);
0 ignored issues
show
It seems like $stream can also be of type false; however, parameter $handle of fwrite() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

29
        fwrite(/** @scrutinizer ignore-type */ $stream, $resource);
Loading history...
30
        fseek($stream, 0);
0 ignored issues
show
It seems like $stream can also be of type false; however, parameter $handle of fseek() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

30
        fseek(/** @scrutinizer ignore-type */ $stream, 0);
Loading history...
31
32
        return new Stream($stream);
33
    }
34
35
    if ($resource instanceof StreamInterface) {
36
        return $resource;
37
    }
38
39
    if (is_callable($resource)) {
40
        return new CallableStream($resource);
0 ignored issues
show
It seems like $resource can also be of type object and resource; however, parameter $callable of Koded\Http\CallableStream::__construct() does only seem to accept callable, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

40
        return new CallableStream(/** @scrutinizer ignore-type */ $resource);
Loading history...
41
    }
42
43
    $type = gettype($resource);
44
45
    if ('resource' === $type) {
46
        return new Stream($resource);
47
    }
48
49
    if ('object' === $type && method_exists($resource, '__toString')) {
50
        return create_stream((string)$resource);
51
    }
52
53
    throw new InvalidArgumentException('Failed to create a stream. '
54
        . 'Expected a file name, StreamInterface instance, or a resource. '
55
        . "Given {$type} type.");
56
}
57
58
/**
59
 * Copies the stream to another stream object.
60
 *
61
 * @param StreamInterface $source      The source stream object
62
 * @param StreamInterface $destination Destination stream object
63
 * @param int             [optional] $length Read up to $length bytes from the source stream.
64
 *                                     Fewer than $length bytes may be returned if underlying stream
65
 *                                     call returns fewer bytes
66
 *
67
 * @return int The total count of bytes copied
68
 */
69
function stream_copy(StreamInterface $source, StreamInterface $destination, int $length = 8192): int
70
{
71
    $bytes = 0;
72
    while (false === $source->eof()) {
73
        $bytes += $destination->write($source->read($length));
74
    }
75
76
    $destination->close();
77
78
    return $bytes;
79
}
80
81
/**
82
 * @param StreamInterface $stream
83
 *
84
 * @return string
85
 * @throws RuntimeException on failure
86
 */
87
function stream_to_string(StreamInterface $stream): string
88
{
89
    $content = '';
90
    $stream->rewind();
91
92
    while (false === $stream->eof()) {
93
        $content .= $stream->read(1048576); // 1MB
94
    }
95
96
    return $content;
97
}
98
99
/**
100
 * Transforms the array to 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
        foreach ($files as $k => $v) {
111
            $list   = $path;
112
            $list[] = $k;
113
114
            if (is_array($v)) {
115
                $file = $sane($v, $file, $list);
116
            } else {
117
                $next = array_splice($list, 1, 1);
118
                $copy = &$file;
119
                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
                    $copy = &$copy[$k];
121
                }
122
                $copy = $v;
123
            }
124
        }
125
126
        return $file;
127
    };
128
129
    return $sane($files);
130
}
131
132
/**
133
 * Preserves the array structure and replaces the
134
 * file description with instance of UploadedFile.
135
 *
136
 * @param array $files Normalized _FILES array
137
 *
138
 * @return array An array tree of UploadedFileInterface instances
139
 */
140
function build_files_array(array $files): array
141
{
142
    foreach ($files as $index => $file) {
143
        if ($file instanceof UploadedFileInterface) {
144
            $files[$index] = $file;
145
        } elseif (isset($file['tmp_name']) && is_array($file)) {
146
            $files[$index] = new UploadedFile($file);
147
        } elseif (is_array($file)) {
148
            $files[$index] = build_files_array($file);
149
            continue;
150
        } else {
151
            throw new InvalidArgumentException('Failed to process the uploaded files. Invalid file structure provided');
152
        }
153
    }
154
155
    return $files;
156
}
157