Completed
Pull Request — master (#5)
by Márk
02:40 queued 37s
created

FilteredStream::read()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 22
ccs 13
cts 13
cp 1
rs 9.2
cc 3
eloc 13
nc 3
nop 1
crap 3
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 = 65536;
17
18
    use StreamDecorator;
19
20
    /**
21
     * @var callable
22
     */
23
    protected $readFilterCallback;
24
25
    /**
26
     * @var resource
27
     */
28
    protected $readFilter;
29
30
    /**
31
     * @var callable
32
     */
33
    protected $writeFilterCallback;
34
35
    /**
36
     * @var resource
37
     */
38
    protected $writeFilter;
39
40
    /**
41
     * Internal buffer.
42
     *
43
     * @var string
44
     */
45
    protected $buffer = '';
46
47
    /**
48
     * @param StreamInterface $stream
49
     * @param null            $readFilterOptions
50
     * @param null            $writeFilterOptions
51
     */
52 32
    public function __construct(StreamInterface $stream, $readFilterOptions = null, $writeFilterOptions = null)
53
    {
54 32
        $this->readFilterCallback = Filter\fun($this->getReadFilter(), $readFilterOptions);
55 32
        $this->writeFilterCallback = Filter\fun($this->getWriteFilter(), $writeFilterOptions);
56 32
        $this->stream = $stream;
57 32
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62 16
    public function read($length)
63
    {
64 16
        if (strlen($this->buffer) >= $length) {
65 7
            $read = substr($this->buffer, 0, $length);
66 7
            $this->buffer = substr($this->buffer, $length);
67
68 7
            return $read;
69
        }
70
71 16
        if ($this->stream->eof()) {
72 10
            $buffer = $this->buffer;
73 10
            $this->buffer = '';
74
75 10
            return $buffer;
76
        }
77
78 16
        $read = $this->buffer;
79 16
        $this->buffer = '';
80 16
        $this->fill();
81
82 16
        return $read.$this->read($length - strlen($read));
83
    }
84
85
    /**
86
     * {@inheritdoc}
87
     */
88 9
    public function eof()
89
    {
90 9
        return $this->stream->eof() && $this->buffer === '';
91
    }
92
93
    /**
94
     * Buffer is filled by reading underlying stream.
95
     *
96
     * Callback is reading once more even if the stream is ended.
97
     * This allow to get last data in the PHP buffer otherwise this
98
     * bug is present : https://bugs.php.net/bug.php?id=48725
99
     */
100 16
    protected function fill()
101
    {
102 16
        $readFilterCallback = $this->readFilterCallback;
103 16
        $this->buffer      .= $readFilterCallback($this->stream->read(self::BUFFER_SIZE));
104
105 16
        if ($this->stream->eof()) {
106 16
            $this->buffer .= $readFilterCallback();
107 16
        }
108 16
    }
109
110
    /**
111
     * {@inheritdoc}
112
     */
113 9
    public function getContents()
114
    {
115 9
        $buffer = '';
116
117 9
        while (!$this->eof()) {
118 9
            $buf = $this->read(1048576);
119
            // Using a loose equality here to match on '' and false.
120 9
            if ($buf == null) {
121
                break;
122
            }
123
124 9
            $buffer .= $buf;
125 9
        }
126
127 9
        return $buffer;
128
    }
129
130
    /**
131
     * Return the read filter name.
132
     *
133
     * @return string
134
     */
135
    abstract public function getReadFilter();
136
137
    /**
138
     * Return the write filter name.
139
     *
140
     * @return mixed
141
     */
142
    abstract public function getWriteFilter();
143
}
144