Completed
Push — v3 ( 4ecdc9...abfb2c )
by Mihail
06:27
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 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
        \fwrite($stream, $resource);
28
        \fseek($stream, 0);
29
        return new Stream($stream);
30
    }
31
    if ($resource instanceof StreamInterface) {
32
        return $resource;
33
    }
34
    if (\is_callable($resource)) {
35
        return new CallableStream($resource);
36
    }
37
    $type = \gettype($resource);
38
    if ('resource' === $type) {
39
        return new Stream($resource);
40
    }
41
    if ('object' === $type && \method_exists($resource, '__toString')) {
42
        return create_stream((string)$resource);
43
    }
44
    throw new \InvalidArgumentException('Failed to create a stream. '
45
        . 'Expected a file name, StreamInterface instance, or a resource. '
46
        . "Given {$type} type.");
47
}
48
49
/**
50
 * Copies the stream to another stream object.
51
 *
52
 * @param StreamInterface $source      The source stream object
53
 * @param StreamInterface $destination Destination stream object
54
 * @param int             [optional] $length Read up to $length bytes from the source stream.
55
 *                                     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(StreamInterface $source, StreamInterface $destination, int $length = 8192): int
61
{
62
    $bytes = 0;
63
    while (false === $source->eof()) {
64
        $bytes += $destination->write($source->read($length));
65
    }
66
    $destination->close();
67
    return $bytes;
68
}
69
70
/**
71
 * @param StreamInterface $stream
72
 *
73
 * @return string
74
 * @throws \RuntimeException on failure
75
 */
76
function stream_to_string(StreamInterface $stream): string
77
{
78
    $content = '';
79
    $stream->rewind();
80
    while (false === $stream->eof()) {
81
        $content .= $stream->read(65536); // 64KB
82
    }
83
    return $content;
84
}
85
86
/**
87
 * Transforms the array to much desired files array structure.
88
 * Deals with any nested level.
89
 *
90
 * @param array $files Typically the $_FILES array
91
 *
92
 * @return array A files array to a sane format
93
 */
94
function normalize_files_array(array $files): array
95
{
96
    $sane = function(array $files, array $file = [], array $path = []) use (&$sane) {
97
        foreach ($files as $k => $v) {
98
            $list   = $path;
99
            $list[] = $k;
100
            if (\is_array($v)) {
101
                $file = $sane($v, $file, $list);
102
            } else {
103
                $next = \array_splice($list, 1, 1);
104
                $copy = &$file;
105
                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...
106
                    $copy = &$copy[$k];
107
                }
108
                $copy = $v;
109
            }
110
        }
111
        return $file;
112
    };
113
114
    return $sane($files);
115
}
116
117
/**
118
 * Preserves the array structure and replaces the
119
 * file description with instance of UploadedFile.
120
 *
121
 * @param array $files Normalized _FILES array
122
 *
123
 * @return array An array tree of UploadedFileInterface instances
124
 */
125
function build_files_array(array $files): array
126
{
127
    foreach ($files as $index => $file) {
128
        if ($file instanceof UploadedFileInterface) {
129
            $files[$index] = $file;
130
        } elseif (isset($file['tmp_name']) && \is_array($file)) {
131
            $files[$index] = new UploadedFile($file);
132
        } elseif (\is_array($file)) {
133
            $files[$index] = build_files_array($file);
134
            continue;
135
        } else {
136
            throw new \InvalidArgumentException('Failed to process the uploaded files. Invalid file structure provided');
137
        }
138
    }
139
    return $files;
140
}
141