Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit aef27f0

Browse files
committed
Merge pull request #57
2 parents 298624b + 67c450b commit aef27f0

21 files changed

+3990
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace MongoDB\Exception;
4+
5+
class GridFSCorruptFileException extends \MongoDB\Driver\Exception\RuntimeException implements Exception
6+
{
7+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace MongoDB\Exception;
4+
5+
class GridFSFileNotFoundException extends \MongoDB\Driver\Exception\RuntimeException implements Exception
6+
{
7+
public function __construct($filename, $namespace)
8+
{
9+
parent::__construct(sprintf('Unable to find file "%s" in namespace "%s"', $filename, $namespace));
10+
}
11+
}

‎src/GridFS/Bucket.php‎

Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
<?php
2+
3+
namespace MongoDB\GridFS;
4+
5+
use MongoDB\BSON\ObjectId;
6+
use MongoDB\Driver\Cursor;
7+
use MongoDB\Driver\Manager;
8+
use MongoDB\Exception\GridFSFileNotFoundException;
9+
use MongoDB\Exception\InvalidArgumentTypeException;
10+
use MongoDB\Operation\Find;
11+
12+
/**
13+
* Bucket provides a public API for interacting with the GridFS files and chunks
14+
* collections.
15+
*
16+
* @api
17+
*/
18+
class Bucket
19+
{
20+
private static $streamWrapper;
21+
22+
private $collectionsWrapper;
23+
private $databaseName;
24+
private $options;
25+
26+
/**
27+
* Constructs a GridFS bucket.
28+
*
29+
* Supported options:
30+
*
31+
* * bucketName (string): The bucket name, which will be used as a prefix
32+
* for the files and chunks collections. Defaults to "fs".
33+
*
34+
* * chunkSizeBytes (integer): The chunk size in bytes. Defaults to
35+
* 261120 (i.e. 255 KiB).
36+
*
37+
* * readPreference (MongoDB\Driver\ReadPreference): Read preference.
38+
*
39+
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
40+
*
41+
* @param Manager $manager Manager instance from the driver
42+
* @param string $databaseName Database name
43+
* @param array $options Bucket options
44+
* @throws InvalidArgumentException
45+
*/
46+
public function __construct(Manager $manager, $databaseName, array $options = [])
47+
{
48+
$options += [
49+
'bucketName' => 'fs',
50+
'chunkSizeBytes' => 261120,
51+
];
52+
53+
if (isset($options['bucketName']) && ! is_string($options['bucketName'])) {
54+
throw new InvalidArgumentTypeException('"bucketName" option', $options['bucketName'], 'string');
55+
}
56+
57+
if (isset($options['chunkSizeBytes']) && ! is_integer($options['chunkSizeBytes'])) {
58+
throw new InvalidArgumentTypeException('"chunkSizeBytes" option', $options['chunkSizeBytes'], 'integer');
59+
}
60+
61+
if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) {
62+
throw new InvalidArgumentTypeException('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
63+
}
64+
65+
if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) {
66+
throw new InvalidArgumentTypeException('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
67+
}
68+
69+
$this->databaseName = (string) $databaseName;
70+
$this->options = $options;
71+
72+
$collectionOptions = array_intersect_key($options, ['readPreference' => 1, 'writeConcern' => 1]);
73+
74+
$this->collectionsWrapper = new GridFSCollectionsWrapper($manager, $databaseName, $options['bucketName'], $collectionOptions);
75+
$this->registerStreamWrapper($manager);
76+
}
77+
78+
/**
79+
* Delete a file from the GridFS bucket.
80+
*
81+
* If the files collection document is not found, this method will still
82+
* attempt to delete orphaned chunks.
83+
*
84+
* @param ObjectId $id ObjectId of the file
85+
* @throws GridFSFileNotFoundException
86+
*/
87+
public function delete(ObjectId $id)
88+
{
89+
$file = $this->collectionsWrapper->getFilesCollection()->findOne(['_id' => $id]);
90+
$this->collectionsWrapper->getFilesCollection()->deleteOne(['_id' => $id]);
91+
$this->collectionsWrapper->getChunksCollection()->deleteMany(['files_id' => $id]);
92+
93+
if ($file === null) {
94+
throw new GridFSFileNotFoundException($id, $this->collectionsWrapper->getFilesCollection()->getNameSpace());
95+
}
96+
97+
}
98+
99+
/**
100+
* Writes the contents of a GridFS file to a writable stream.
101+
*
102+
* @param ObjectId $id ObjectId of the file
103+
* @param resource $destination Writable Stream
104+
* @throws GridFSFileNotFoundException
105+
*/
106+
public function downloadToStream(ObjectId $id, $destination)
107+
{
108+
$file = $this->collectionsWrapper->getFilesCollection()->findOne(
109+
['_id' => $id],
110+
['typeMap' => ['root' => 'stdClass']]
111+
);
112+
113+
if ($file === null) {
114+
throw new GridFSFileNotFoundException($id, $this->collectionsWrapper->getFilesCollection()->getNameSpace());
115+
}
116+
117+
$gridFsStream = new GridFSDownload($this->collectionsWrapper, $file);
118+
$gridFsStream->downloadToStream($destination);
119+
}
120+
121+
/**
122+
* Writes the contents of a GridFS file, which is selected by name and
123+
* revision, to a writable stream.
124+
*
125+
* Supported options:
126+
*
127+
* * revision (integer): Which revision (i.e. documents with the same
128+
* filename and different uploadDate) of the file to retrieve. Defaults
129+
* to -1 (i.e. the most recent revision).
130+
*
131+
* Revision numbers are defined as follows:
132+
*
133+
* * 0 = the original stored file
134+
* * 1 = the first revision
135+
* * 2 = the second revision
136+
* * etc...
137+
* * -2 = the second most recent revision
138+
* * -1 = the most recent revision
139+
*
140+
* @param string $filename File name
141+
* @param resource $destination Writable Stream
142+
* @param array $options Download options
143+
* @throws GridFSFileNotFoundException
144+
*/
145+
public function downloadToStreamByName($filename, $destination, array $options = [])
146+
{
147+
$options += ['revision' => -1];
148+
$file = $this->findFileRevision($filename, $options['revision']);
149+
$gridFsStream = new GridFSDownload($this->collectionsWrapper, $file);
150+
$gridFsStream->downloadToStream($destination);
151+
}
152+
153+
/**
154+
* Drops the files and chunks collection associated with GridFS this bucket
155+
*
156+
*/
157+
158+
public function drop()
159+
{
160+
$this->collectionsWrapper->dropCollections();
161+
}
162+
163+
/**
164+
* Find files from the GridFS bucket's files collection.
165+
*
166+
* @see Find::__construct() for supported options
167+
* @param array|object $filter Query by which to filter documents
168+
* @param array $options Additional options
169+
* @return Cursor
170+
*/
171+
public function find($filter, array $options = [])
172+
{
173+
return $this->collectionsWrapper->getFilesCollection()->find($filter, $options);
174+
}
175+
176+
public function getCollectionsWrapper()
177+
{
178+
return $this->collectionsWrapper;
179+
}
180+
181+
public function getDatabaseName()
182+
{
183+
return $this->databaseName;
184+
}
185+
186+
/**
187+
* Gets the ID of the GridFS file associated with a stream.
188+
*
189+
* @param resource $stream GridFS stream
190+
* @return mixed
191+
*/
192+
public function getIdFromStream($stream)
193+
{
194+
$metadata = stream_get_meta_data($stream);
195+
196+
if ($metadata['wrapper_data'] instanceof StreamWrapper) {
197+
return $metadata['wrapper_data']->getId();
198+
}
199+
200+
return;
201+
}
202+
203+
/**
204+
* Opens a readable stream for reading a GridFS file.
205+
*
206+
* @param ObjectId $id ObjectId of the file
207+
* @return resource
208+
* @throws GridFSFileNotFoundException
209+
*/
210+
public function openDownloadStream(ObjectId $id)
211+
{
212+
$file = $this->collectionsWrapper->getFilesCollection()->findOne(
213+
['_id' => $id],
214+
['typeMap' => ['root' => 'stdClass']]
215+
);
216+
217+
if ($file === null) {
218+
throw new GridFSFileNotFoundException($id, $this->collectionsWrapper->getFilesCollection()->getNameSpace());
219+
}
220+
221+
return $this->openDownloadStreamByFile($file);
222+
}
223+
224+
/**
225+
* Opens a readable stream stream to read a GridFS file, which is selected
226+
* by name and revision.
227+
*
228+
* Supported options:
229+
*
230+
* * revision (integer): Which revision (i.e. documents with the same
231+
* filename and different uploadDate) of the file to retrieve. Defaults
232+
* to -1 (i.e. the most recent revision).
233+
*
234+
* Revision numbers are defined as follows:
235+
*
236+
* * 0 = the original stored file
237+
* * 1 = the first revision
238+
* * 2 = the second revision
239+
* * etc...
240+
* * -2 = the second most recent revision
241+
* * -1 = the most recent revision
242+
*
243+
* @param string $filename File name
244+
* @param array $options Download options
245+
* @return resource
246+
* @throws GridFSFileNotFoundException
247+
*/
248+
public function openDownloadStreamByName($filename, array $options = [])
249+
{
250+
$options += ['revision' => -1];
251+
$file = $this->findFileRevision($filename, $options['revision']);
252+
253+
return $this->openDownloadStreamByFile($file);
254+
}
255+
256+
/**
257+
* Opens a writable stream for writing a GridFS file.
258+
*
259+
* Supported options:
260+
*
261+
* * chunkSizeBytes (integer): The chunk size in bytes. Defaults to the
262+
* bucket's chunk size.
263+
*
264+
* @param string $filename File name
265+
* @param array $options Stream options
266+
* @return resource
267+
*/
268+
public function openUploadStream($filename, array $options = [])
269+
{
270+
$options += ['chunkSizeBytes' => $this->options['chunkSizeBytes']];
271+
272+
$streamOptions = [
273+
'collectionsWrapper' => $this->collectionsWrapper,
274+
'uploadOptions' => $options,
275+
];
276+
277+
$context = stream_context_create(['gridfs' => $streamOptions]);
278+
279+
return fopen(sprintf('gridfs://%s/%s', $this->databaseName, $filename), 'w', false, $context);
280+
}
281+
282+
/**
283+
* Renames the GridFS file with the specified ID.
284+
*
285+
* @param ObjectId $id ID of the file to rename
286+
* @param string $newFilename New file name
287+
* @throws GridFSFileNotFoundException
288+
*/
289+
public function rename(ObjectId $id, $newFilename)
290+
{
291+
$filesCollection = $this->collectionsWrapper->getFilesCollection();
292+
$result = $filesCollection->updateOne(['_id' => $id], ['$set' => ['filename' => $newFilename]]);
293+
if($result->getModifiedCount() == 0) {
294+
throw new GridFSFileNotFoundException($id, $this->collectionsWrapper->getFilesCollection()->getNameSpace());
295+
}
296+
}
297+
298+
/**
299+
* Writes the contents of a readable stream to a GridFS file.
300+
*
301+
* Supported options:
302+
*
303+
* * chunkSizeBytes (integer): The chunk size in bytes. Defaults to the
304+
* bucket's chunk size.
305+
*
306+
* @param string $filename File name
307+
* @param resource $source Readable stream
308+
* @param array $options Stream options
309+
* @return ObjectId
310+
*/
311+
public function uploadFromStream($filename, $source, array $options = [])
312+
{
313+
$options += ['chunkSizeBytes' => $this->options['chunkSizeBytes']];
314+
$gridFsStream = new GridFSUpload($this->collectionsWrapper, $filename, $options);
315+
316+
return $gridFsStream->uploadFromStream($source);
317+
}
318+
319+
private function findFileRevision($filename, $revision)
320+
{
321+
if ($revision < 0) {
322+
$skip = abs($revision) - 1;
323+
$sortOrder = -1;
324+
} else {
325+
$skip = $revision;
326+
$sortOrder = 1;
327+
}
328+
329+
$filesCollection = $this->collectionsWrapper->getFilesCollection();
330+
$file = $filesCollection->findOne(
331+
['filename' => $filename],
332+
[
333+
'skip' => $skip,
334+
'sort' => ['uploadDate' => $sortOrder],
335+
'typeMap' => ['root' => 'stdClass'],
336+
]
337+
);
338+
339+
if ($file === null) {
340+
throw new GridFSFileNotFoundException($filename, $filesCollection->getNameSpace());
341+
}
342+
343+
return $file;
344+
}
345+
346+
private function openDownloadStreamByFile($file)
347+
{
348+
$options = [
349+
'collectionsWrapper' => $this->collectionsWrapper,
350+
'file' => $file,
351+
];
352+
353+
$context = stream_context_create(['gridfs' => $options]);
354+
355+
return fopen(sprintf('gridfs://%s/%s', $this->databaseName, $file->filename), 'r', false, $context);
356+
}
357+
358+
private function registerStreamWrapper(Manager $manager)
359+
{
360+
if (isset(self::$streamWrapper)) {
361+
return;
362+
}
363+
364+
self::$streamWrapper = new StreamWrapper();
365+
self::$streamWrapper->register($manager);
366+
}
367+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /