Completed
Push — v3 ( 4ecdc9...abfb2c )
by Mihail
06:27
created

functions.php (2 issues)

Labels
Severity
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 The string that is to be written
21
 * @param string                                        $mode Type of access to the stream
22
 *
23
 * @return StreamInterface
24
 */
25
function create_stream($resource, string $mode = 'r+b'): StreamInterface
26
{
27
    if (null === $resource || is_string($resource)) {
28
        $stream = fopen('php://temp', $mode);
29
        fwrite($stream, $resource);
0 ignored issues
show
$resource of type null is incompatible with the type string expected by parameter $data of fwrite(). ( 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($stream, /** @scrutinizer ignore-type */ $resource);
Loading history...
30
        fseek($stream, 0);
31
        return new Stream($stream);
32
    }
33
    if ($resource instanceof StreamInterface) {
34
        return $resource;
35
    }
36
    if (is_callable($resource)) {
37
        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

37
        return new CallableStream(/** @scrutinizer ignore-type */ $resource);
Loading history...
38
    }
39
    $type = gettype($resource);
40
    if ('resource' === $type) {
41
        return new Stream($resource);
42
    }
43
    if ('object' === $type && method_exists($resource, '__toString')) {
44
        return create_stream((string)$resource);
45
    }
46
    throw new InvalidArgumentException('Failed to create a stream. '
47
        . 'Expected a file name, StreamInterface instance, or a resource. '
48
        . "Given {$type} type.");
49
}
50
51
/**
52
 * Copies the stream to another stream object.
53
 *
54
 * @param StreamInterface $source      The source stream object
55
 * @param StreamInterface $destination Destination stream object
56
 * @param int             [optional] $length Read up to $length bytes from the source stream.
57
 *                                     Fewer than $length bytes may be returned if underlying stream
58
 *                                     call returns fewer bytes
59
 *
60
 * @return int The total count of bytes copied
61
 */
62
function stream_copy(StreamInterface $source, StreamInterface $destination, int $length = 8192): int
63
{
64
    $bytes = 0;
65
    while (false === $source->eof()) {
66
        $bytes += $destination->write($source->read($length));
67
    }
68
    $destination->close();
69
    return $bytes;
70
}
71
72
/**
73
 * @param StreamInterface $stream
74
 *
75
 * @return string
76
 * @throws RuntimeException on failure
77
 */
78
function stream_to_string(StreamInterface $stream): string
79
{
80
    $content = '';
81
    $stream->rewind();
82
    while (false === $stream->eof()) {
83
        $content .= $stream->read(1048576); // 1MB
84
    }
85
    return $content;
86
}
87
88
/**
89
 * Transforms the array to much desired files array structure.
90
 * Deals with any nested level.
91
 *
92
 * @param array $files Typically the $_FILES array
93
 *
94
 * @return array A files array to a sane format
95
 */
96
function normalize_files_array(array $files): array
97
{
98
    $sane = function(array $files, array $file = [], array $path = []) use (&$sane) {
99
        foreach ($files as $k => $v) {
100
            $list   = $path;
101
            $list[] = $k;
102
            if (is_array($v)) {
103
                $file = $sane($v, $file, $list);
104
            } else {
105
                $next = array_splice($list, 1, 1);
106
                $copy = &$file;
107
                foreach (array_merge($list, $next) as $k) {
108
                    $copy = &$copy[$k];
109
                }
110
                $copy = $v;
111
            }
112
        }
113
        return $file;
114
    };
115
116
    return $sane($files);
117
}
118
119
/**
120
 * Preserves the array structure and replaces the
121
 * file description with instance of UploadedFile.
122
 *
123
 * @param array $files Normalized _FILES array
124
 *
125
 * @return array An array tree of UploadedFileInterface instances
126
 */
127
function build_files_array(array $files): array
128
{
129
    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