Skip to content

Commit 25580cb

Browse files
committed
Merge pull request #325
2 parents 90967fc + aa125b3 commit 25580cb

File tree

6 files changed

+144
-9
lines changed

6 files changed

+144
-9
lines changed

src/GridFS/ReadableStream.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,44 @@ public function readBytes($length)
166166
return $data;
167167
}
168168

169+
/**
170+
* Seeks the chunk and buffer offsets for the next read operation.
171+
*
172+
* @param integer $offset
173+
* @throws InvalidArgumentException if $offset is out of range
174+
*/
175+
public function seek($offset)
176+
{
177+
if ($offset < 0 || $offset > $this->file->length) {
178+
throw new InvalidArgumentException(sprintf('$offset must be >= 0 and <= %d; given: %d', $length, $offset));
179+
}
180+
181+
/* Compute the offsets for the chunk and buffer (i.e. chunk data) from
182+
* which we will expect to read after seeking. If the chunk offset
183+
* changed, we'll also need to reset the buffer.
184+
*/
185+
$lastChunkOffset = $this->chunkOffset;
186+
$this->chunkOffset = (integer) floor($offset / $this->chunkSize);
187+
$this->bufferOffset = $offset % $this->chunkSize;
188+
189+
if ($lastChunkOffset !== $this->chunkOffset) {
190+
$this->buffer = null;
191+
$this->chunksIterator = null;
192+
}
193+
}
194+
195+
/**
196+
* Return the current position of the stream.
197+
*
198+
* This is the offset within the stream where the next byte would be read.
199+
*
200+
* @return integer
201+
*/
202+
public function tell()
203+
{
204+
return ($this->chunkOffset * $this->chunkSize) + $this->bufferOffset;
205+
}
206+
169207
/**
170208
* Initialize the buffer to the current chunk's data.
171209
*

src/GridFS/StreamWrapper.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,40 @@ public function stream_read($length)
136136
}
137137
}
138138

139+
/**
140+
* Return the current position of the stream.
141+
*
142+
* @see http://php.net/manual/en/streamwrapper.stream-seek.php
143+
* @param integer $offset Stream offset to seek to
144+
* @param integer $whence One of SEEK_SET, SEEK_CUR, or SEEK_END
145+
* @return boolean True if the position was updated and false otherwise
146+
*/
147+
public function stream_seek($offset, $whence = \SEEK_SET)
148+
{
149+
$size = $this->stream->getSize();
150+
151+
if ($whence === \SEEK_CUR) {
152+
$offset += $this->stream->tell();
153+
}
154+
155+
if ($whence === \SEEK_END) {
156+
$offset += $size;
157+
}
158+
159+
// WritableStreams are always positioned at the end of the stream
160+
if ($this->stream instanceof WritableStream) {
161+
return $offset === $size;
162+
}
163+
164+
if ($offset < 0 || $offset > $size) {
165+
return false;
166+
}
167+
168+
$this->stream->seek($offset);
169+
170+
return true;
171+
}
172+
139173
/**
140174
* Return information about the stream.
141175
*
@@ -166,6 +200,17 @@ public function stream_stat()
166200
return $stat;
167201
}
168202

203+
/**
204+
* Return the current position of the stream.
205+
*
206+
* @see http://php.net/manual/en/streamwrapper.stream-tell.php
207+
* @return integer The current position of the stream
208+
*/
209+
public function stream_tell()
210+
{
211+
return $this->stream->tell();
212+
}
213+
169214
/**
170215
* Write bytes to the stream.
171216
*

src/GridFS/WritableStream.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,21 @@ public function getSize()
161161
return $this->length + strlen($this->buffer);
162162
}
163163

164+
/**
165+
* Return the current position of the stream.
166+
*
167+
* This is the offset within the stream where the next byte would be
168+
* written. Since seeking is not supported and writes are appended, this is
169+
* always the end of the stream.
170+
*
171+
* @see WriteableStream::getSize()
172+
* @return integer
173+
*/
174+
public function tell()
175+
{
176+
return $this->getSize();
177+
}
178+
164179
/**
165180
* Inserts binary data into GridFS via chunks.
166181
*

tests/GridFS/BucketFunctionalTest.php

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,6 @@ public function testDownloadToStream($input)
187187
$id = $this->bucket->uploadFromStream('filename', $this->createStream($input));
188188
$destination = $this->createStream();
189189
$this->bucket->downloadToStream($id, $destination);
190-
rewind($destination);
191190

192191
$this->assertStreamContents($input, $destination);
193192
}
@@ -222,37 +221,30 @@ public function testDownloadToStreamByName()
222221

223222
$destination = $this->createStream();
224223
$this->bucket->downloadToStreamByName('filename', $destination);
225-
rewind($destination);
226224
$this->assertStreamContents('baz', $destination);
227225

228226
$destination = $this->createStream();
229227
$this->bucket->downloadToStreamByName('filename', $destination, ['revision' => -3]);
230-
rewind($destination);
231228
$this->assertStreamContents('foo', $destination);
232229

233230
$destination = $this->createStream();
234231
$this->bucket->downloadToStreamByName('filename', $destination, ['revision' => -2]);
235-
rewind($destination);
236232
$this->assertStreamContents('bar', $destination);
237233

238234
$destination = $this->createStream();
239235
$this->bucket->downloadToStreamByName('filename', $destination, ['revision' => -1]);
240-
rewind($destination);
241236
$this->assertStreamContents('baz', $destination);
242237

243238
$destination = $this->createStream();
244239
$this->bucket->downloadToStreamByName('filename', $destination, ['revision' => 0]);
245-
rewind($destination);
246240
$this->assertStreamContents('foo', $destination);
247241

248242
$destination = $this->createStream();
249243
$this->bucket->downloadToStreamByName('filename', $destination, ['revision' => 1]);
250-
rewind($destination);
251244
$this->assertStreamContents('bar', $destination);
252245

253246
$destination = $this->createStream();
254247
$this->bucket->downloadToStreamByName('filename', $destination, ['revision' => 2]);
255-
rewind($destination);
256248
$this->assertStreamContents('baz', $destination);
257249
}
258250

tests/GridFS/FunctionalTestCase.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ protected function assertStreamContents($expectedContents, $stream)
3838
{
3939
$this->assertInternalType('resource', $stream);
4040
$this->assertSame('stream', get_resource_type($stream));
41-
$this->assertEquals($expectedContents, stream_get_contents($stream));
41+
$this->assertEquals($expectedContents, stream_get_contents($stream, -1, 0));
4242
}
4343

4444
/**

tests/GridFS/StreamWrapperFunctionalTest.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,32 @@ public function testReadableStreamRead()
5050
$this->assertSame('', fread($stream, 3));
5151
}
5252

53+
public function testReadableStreamSeek()
54+
{
55+
$stream = $this->bucket->openDownloadStream('length-10');
56+
57+
$this->assertSame(0, fseek($stream, 2, \SEEK_SET));
58+
$this->assertSame('cde', fread($stream, 3));
59+
$this->assertSame(0, fseek($stream, 10, \SEEK_SET));
60+
$this->assertSame('', fread($stream, 3));
61+
$this->assertSame(-1, fseek($stream, -1, \SEEK_SET));
62+
$this->assertSame(-1, fseek($stream, 11, \SEEK_SET));
63+
64+
$this->assertSame(0, fseek($stream, -5, \SEEK_CUR));
65+
$this->assertSame('fgh', fread($stream, 3));
66+
$this->assertSame(0, fseek($stream, 1, \SEEK_CUR));
67+
$this->assertSame('j', fread($stream, 3));
68+
$this->assertSame(-1, fseek($stream, 1, \SEEK_CUR));
69+
$this->assertSame(-1, fseek($stream, -11, \SEEK_CUR));
70+
71+
$this->assertSame(0, fseek($stream, 0, \SEEK_END));
72+
$this->assertSame('', fread($stream, 3));
73+
$this->assertSame(0, fseek($stream, -8, \SEEK_END));
74+
$this->assertSame('cde', fread($stream, 3));
75+
$this->assertSame(-1, fseek($stream, -11, \SEEK_END));
76+
$this->assertSame(-1, fseek($stream, 1, \SEEK_END));
77+
}
78+
5379
public function testReadableStreamStat()
5480
{
5581
$stream = $this->bucket->openDownloadStream('length-10');
@@ -102,6 +128,25 @@ public function testWritableStreamRead()
102128
$this->assertSame('', fread($stream, 8192));
103129
}
104130

131+
public function testWritableStreamSeek()
132+
{
133+
$stream = $this->bucket->openUploadStream('filename');
134+
135+
$this->assertSame(6, fwrite($stream, 'foobar'));
136+
137+
$this->assertSame(-1, fseek($stream, 0, \SEEK_SET));
138+
$this->assertSame(-1, fseek($stream, 7, \SEEK_SET));
139+
$this->assertSame(0, fseek($stream, 6, \SEEK_SET));
140+
141+
$this->assertSame(0, fseek($stream, 0, \SEEK_CUR));
142+
$this->assertSame(-1, fseek($stream, -1, \SEEK_CUR));
143+
$this->assertSame(-1, fseek($stream, 1, \SEEK_CUR));
144+
145+
$this->assertSame(0, fseek($stream, 0, \SEEK_END));
146+
$this->assertSame(-1, fseek($stream, -1, \SEEK_END));
147+
$this->assertSame(-1, fseek($stream, 1, \SEEK_END));
148+
}
149+
105150
public function testWritableStreamStat()
106151
{
107152
$currentTimestamp = time();

0 commit comments

Comments
 (0)