Completed
Pull Request — master (#100)
by Joel
02:28
created

FilteredStream::rewind()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
namespace Http\Message\Encoding;
4
5
use Clue\StreamFilter as Filter;
6
use Http\Message\Decorator\StreamDecorator;
7
use Psr\Http\Message\StreamInterface;
8
9
/**
10
 * A filtered stream has a filter for filtering output and a filter for filtering input made to a underlying stream.
11
 *
12
 * @author Joel Wurtz <[email protected]>
13
 */
14
abstract class FilteredStream implements StreamInterface
15
{
16
    const BUFFER_SIZE = 8192;
17
18
    use StreamDecorator;
19
20
    /**
21
     * @var callable
22
     */
23
    protected $readFilterCallback;
24
25
    /**
26
     * @var resource
27
     *
28
     * @deprecated since version 1.5, will be removed in 2.0
29
     */
30
    protected $readFilter;
31
32
    /**
33
     * @var callable
34
     *
35
     * @deprecated since version 1.5, will be removed in 2.0
36
     */
37
    protected $writeFilterCallback;
38
39
    /**
40
     * @var resource
41
     *
42
     * @deprecated since version 1.5, will be removed in 2.0
43
     */
44
    protected $writeFilter;
45
46
    /**
47
     * Internal buffer.
48
     *
49
     * @var string
50
     */
51
    protected $buffer = '';
52
53
    /**
54
     * @param StreamInterface $stream
55
     * @param mixed|null      $readFilterOptions
56
     * @param mixed|null      $writeFilterOptions deprecated since 1.5, will be removed in 2.0
57
     */
58 40
    public function __construct(StreamInterface $stream, $readFilterOptions = null, $writeFilterOptions = null)
59
    {
60 40
        $this->readFilterCallback = Filter\fun($this->readFilter(), $readFilterOptions);
61 40
        $this->writeFilterCallback = Filter\fun($this->writeFilter(), $writeFilterOptions);
0 ignored issues
show
Deprecated Code introduced by
The property Http\Message\Encoding\Fi...m::$writeFilterCallback has been deprecated with message: since version 1.5, will be removed in 2.0

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
62
63 40
        if (null !== $writeFilterOptions) {
64 30
            @trigger_error('The $writeFilterOptions argument is deprecated since version 1.5 and will be removed in 2.0.', E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
65 30
        }
66
67 40
        $this->stream = $stream;
68 40
    }
69
70
    /**
71
     * {@inheritdoc}
72
     */
73 16
    public function read($length)
74
    {
75 16
        if (strlen($this->buffer) >= $length) {
76 7
            $read = substr($this->buffer, 0, $length);
77 7
            $this->buffer = substr($this->buffer, $length);
78
79 7
            return $read;
80
        }
81
82 16
        if ($this->stream->eof()) {
83 10
            $buffer = $this->buffer;
84 10
            $this->buffer = '';
85
86 10
            return $buffer;
87
        }
88
89 16
        $read = $this->buffer;
90 16
        $this->buffer = '';
91 16
        $this->fill();
92
93 16
        return $read.$this->read($length - strlen($read));
94
    }
95
96
    /**
97
     * {@inheritdoc}
98
     */
99 9
    public function eof()
100
    {
101 9
        return $this->stream->eof() && '' === $this->buffer;
102
    }
103
104
    /**
105
     * Buffer is filled by reading underlying stream.
106
     *
107
     * Callback is reading once more even if the stream is ended.
108
     * This allow to get last data in the PHP buffer otherwise this
109
     * bug is present : https://bugs.php.net/bug.php?id=48725
110
     */
111 16
    protected function fill()
112
    {
113 16
        $readFilterCallback = $this->readFilterCallback;
114 16
        $this->buffer .= $readFilterCallback($this->stream->read(self::BUFFER_SIZE));
115
116 16
        if ($this->stream->eof()) {
117 16
            $this->buffer .= $readFilterCallback();
118 16
        }
119 16
    }
120
121
    /**
122
     * {@inheritdoc}
123
     */
124 9
    public function getContents()
125
    {
126 9
        $buffer = '';
127
128 9
        while (!$this->eof()) {
129 9
            $buf = $this->read(self::BUFFER_SIZE);
130
            // Using a loose equality here to match on '' and false.
131 9
            if (null == $buf) {
132
                break;
133
            }
134
135 9
            $buffer .= $buf;
136 9
        }
137
138 9
        return $buffer;
139
    }
140
141
    /**
142
     * {@inheritdoc}
143
     */
144 8
    public function getSize()
145
    {
146 8
        return;
147
    }
148
149
    /**
150
     * {@inheritdoc}
151
     */
152
    public function __toString()
153
    {
154
        return $this->getContents();
155
    }
156
157
    /**
158
     * {@inheritdoc}
159
     */
160
    public function isSeekable()
161
    {
162
        return false;
163
    }
164
165
    /**
166
     * {@inheritdoc}
167
     */
168
    public function rewind()
169
    {
170
        throw new \RuntimeException('Cannot rewind a filtered stream');
171
    }
172
173
    /**
174
     * {@inheritdoc}
175
     */
176
    public function seek($offset, $whence = SEEK_SET)
177
    {
178
        throw new \RuntimeException('Cannot seek a filtered stream');
179
    }
180
181
    /**
182
     * Returns the read filter name.
183
     *
184
     * @return string
185
     *
186
     * @deprecated since version 1.5, will be removed in 2.0
187
     */
188
    public function getReadFilter()
189
    {
190
        @trigger_error('The '.__CLASS__.'::'.__METHOD__.' method is deprecated since version 1.5 and will be removed in 2.0.', E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
191
192
        return $this->readFilter();
193
    }
194
195
    /**
196
     * Returns the write filter name.
197
     *
198
     * @return string
199
     */
200
    abstract protected function readFilter();
201
202
    /**
203
     * Returns the write filter name.
204
     *
205
     * @return string
206
     *
207
     * @deprecated since version 1.5, will be removed in 2.0
208
     */
209
    public function getWriteFilter()
210
    {
211
        @trigger_error('The '.__CLASS__.'::'.__METHOD__.' method is deprecated since version 1.5 and will be removed in 2.0.', E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
212
213
        return $this->writeFilter();
214
    }
215
216
    /**
217
     * Returns the write filter name.
218
     *
219
     * @return string
220
     */
221
    abstract protected function writeFilter();
222
}
223