Subversion Repositories php-qbpwcf

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 liveuser 1
<?php
2
 
3
namespace GuzzleHttp\Psr7;
4
 
5
use Psr\Http\Message\StreamInterface;
6
 
7
 
8
/**
9
 * Decorator used to return only a subset of a stream
10
 */
11
class LimitStream implements StreamInterface
12
{
13
    use StreamDecoratorTrait;
14
 
15
    /** @var int Offset to start reading from */
16
    private $offset;
17
 
18
    /** @var int Limit the number of bytes that can be read */
19
    private $limit;
20
 
21
    /**
22
     * @param StreamInterface $stream Stream to wrap
23
     * @param int             $limit  Total number of bytes to allow to be read
24
     *                                from the stream. Pass -1 for no limit.
25
     * @param int             $offset Position to seek to before reading (only
26
     *                                works on seekable streams).
27
     */
28
    public function __construct(
29
        StreamInterface $stream,
30
        $limit = -1,
31
        $offset = 0
32
    ) {
33
        $this->stream = $stream;
34
        $this->setLimit($limit);
35
        $this->setOffset($offset);
36
    }
37
 
38
    public function eof()
39
    {
40
        // Always return true if the underlying stream is EOF
41
        if ($this->stream->eof()) {
42
            return true;
43
        }
44
 
45
        // No limit and the underlying stream is not at EOF
46
        if ($this->limit == -1) {
47
            return false;
48
        }
49
 
50
        return $this->stream->tell() >= $this->offset + $this->limit;
51
    }
52
 
53
    /**
54
     * Returns the size of the limited subset of data
55
     * {@inheritdoc}
56
     */
57
    public function getSize()
58
    {
59
        if (null === ($length = $this->stream->getSize())) {
60
            return null;
61
        } elseif ($this->limit == -1) {
62
            return $length - $this->offset;
63
        } else {
64
            return min($this->limit, $length - $this->offset);
65
        }
66
    }
67
 
68
    /**
69
     * Allow for a bounded seek on the read limited stream
70
     * {@inheritdoc}
71
     */
72
    public function seek($offset, $whence = SEEK_SET)
73
    {
74
        if ($whence !== SEEK_SET || $offset < 0) {
75
            throw new \RuntimeException(sprintf(
76
                'Cannot seek to offset %s with whence %s',
77
                $offset,
78
                $whence
79
            ));
80
        }
81
 
82
        $offset += $this->offset;
83
 
84
        if ($this->limit !== -1) {
85
            if ($offset > $this->offset + $this->limit) {
86
                $offset = $this->offset + $this->limit;
87
            }
88
        }
89
 
90
        $this->stream->seek($offset);
91
    }
92
 
93
    /**
94
     * Give a relative tell()
95
     * {@inheritdoc}
96
     */
97
    public function tell()
98
    {
99
        return $this->stream->tell() - $this->offset;
100
    }
101
 
102
    /**
103
     * Set the offset to start limiting from
104
     *
105
     * @param int $offset Offset to seek to and begin byte limiting from
106
     *
107
     * @throws \RuntimeException if the stream cannot be seeked.
108
     */
109
    public function setOffset($offset)
110
    {
111
        $current = $this->stream->tell();
112
 
113
        if ($current !== $offset) {
114
            // If the stream cannot seek to the offset position, then read to it
115
            if ($this->stream->isSeekable()) {
116
                $this->stream->seek($offset);
117
            } elseif ($current > $offset) {
118
                throw new \RuntimeException("Could not seek to stream offset $offset");
119
            } else {
120
                $this->stream->read($offset - $current);
121
            }
122
        }
123
 
124
        $this->offset = $offset;
125
    }
126
 
127
    /**
128
     * Set the limit of bytes that the decorator allows to be read from the
129
     * stream.
130
     *
131
     * @param int $limit Number of bytes to allow to be read from the stream.
132
     *                   Use -1 for no limit.
133
     */
134
    public function setLimit($limit)
135
    {
136
        $this->limit = $limit;
137
    }
138
 
139
    public function read($length)
140
    {
141
        if ($this->limit == -1) {
142
            return $this->stream->read($length);
143
        }
144
 
145
        // Check if the current position is less than the total allowed
146
        // bytes + original offset
147
        $remaining = ($this->offset + $this->limit) - $this->stream->tell();
148
        if ($remaining > 0) {
149
            // Only return the amount of requested data, ensuring that the byte
150
            // limit is not exceeded
151
            return $this->stream->read(min($remaining, $length));
152
        }
153
 
154
        return '';
155
    }
156
}