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 56023b0

Browse files
author
Will Banfield
committed
PHPLIB-146: Implement GridFS upload, plus initial GridFS commit
1 parent 6faa366 commit 56023b0

File tree

18 files changed

+2837
-3
lines changed

18 files changed

+2837
-3
lines changed

‎src/GridFS/Bucket.php‎

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
<?php
2+
namespace MongoDB\GridFS;
3+
4+
use MongoDB\Collection;
5+
use MongoDB\Database;
6+
use MongoDB\BSON\ObjectId;
7+
use MongoDB\Driver\ReadPreference;
8+
use MongoDB\Driver\WriteConcern;
9+
use MongoDB\Driver\Manager;
10+
use MongoDB\Exception\InvalidArgumentException;
11+
use MongoDB\Exception\InvalidArgumentTypeException;
12+
use MongoDB\Exception\RuntimeException;
13+
use MongoDB\Exception\UnexpectedValueException;
14+
/**
15+
* Bucket abstracts the GridFS files and chunks collections.
16+
*
17+
* @api
18+
*/
19+
class Bucket
20+
{
21+
private $databaseName;
22+
private $options;
23+
private $filesCollection;
24+
private $chunksCollection;
25+
private $indexChecker;
26+
private $ensuredIndexes = false;
27+
/**
28+
* Constructs a GridFS bucket.
29+
*
30+
* Supported options:
31+
*
32+
* * bucketName (string): The bucket name, which will be used as a prefix
33+
* for the files and chunks collections. Defaults to "fs".
34+
*
35+
* * chunkSizeBytes (integer): The chunk size in bytes. Defaults to
36+
* 261120 (i.e. 255 KiB).
37+
*
38+
* * readPreference (MongoDB\Driver\ReadPreference): Read preference.
39+
*
40+
* * writeConcern (MongoDB\Driver\WriteConcern): Write concern.
41+
*
42+
* @param Manager $manager Manager instance from the driver
43+
* @param string $databaseName Database name
44+
* @param array $options Bucket options
45+
* @throws InvalidArgumentException
46+
*/
47+
public function __construct(Manager $manager, $databaseName, array $options = [])
48+
{
49+
$collectionOptions = [];
50+
$options += [
51+
'bucketName' => 'fs',
52+
'chunkSizeBytes' => 261120,
53+
];
54+
if (isset($options['bucketName']) && ! is_string($options['bucketName'])) {
55+
throw new InvalidArgumentTypeException('"bucketName" option', $options['bucketName'], 'string');
56+
}
57+
if (isset($options['chunkSizeBytes']) && ! is_integer($options['chunkSizeBytes'])) {
58+
throw new InvalidArgumentTypeException('"chunkSizeBytes" option', $options['chunkSizeBytes'], 'integer');
59+
}
60+
if (isset($options['readPreference'])) {
61+
if (! $options['readPreference'] instanceof ReadPreference) {
62+
throw new InvalidArgumentTypeException('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
63+
} else {
64+
$collectionOptions['readPreference'] = $options['readPreference'];
65+
}
66+
}
67+
if (isset($options['writeConcern'])) {
68+
if (! $options['writeConcern'] instanceof WriteConcern) {
69+
throw new InvalidArgumentTypeException('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
70+
} else {
71+
$collectionOptions['writeConcern'] = $options['writeConcern'];
72+
}
73+
}
74+
$this->databaseName = (string) $databaseName;
75+
$this->options = $options;
76+
77+
$this->filesCollection = new Collection(
78+
$manager,
79+
sprintf('%s.%s.files', $this->databaseName, $options['bucketName']),
80+
$collectionOptions
81+
);
82+
$this->chunksCollection = new Collection(
83+
$manager,
84+
sprintf('%s.%s.chunks', $this->databaseName, $options['bucketName']),
85+
$collectionOptions
86+
);
87+
}
88+
/**
89+
* Opens a Stream for reading the contents of a file specified by ID.
90+
*
91+
* @param ObjectId $id
92+
* @return Stream
93+
*/
94+
public function openDownloadStream(ObjectId $id)
95+
{
96+
fopen('gridfs://$this->databaseName/$id', 'r');
97+
}
98+
/**
99+
* Downloads the contents of the stored file specified by id and writes
100+
* the contents to the destination Stream.
101+
* @param ObjectId $id GridFS File Id
102+
* @param Stream $destination Destination Stream
103+
*/
104+
public function downloadToStream(ObjectId $id, $destination)
105+
{
106+
$result = $this->filesCollection->findOne(['_id' => $id]);
107+
if ($result == null) {
108+
return;
109+
}
110+
if ($result->length == 0){
111+
return;
112+
}
113+
114+
$n=0;
115+
$results = $this->chunksCollection->find(['files_id' => $result->_id]);
116+
foreach ($results as $chunk) {
117+
if ($chunk->n != $n) {
118+
return;
119+
}
120+
fwrite($destination, $chunk->data);
121+
$n++;
122+
}
123+
}
124+
/**
125+
* Return the chunkSizeBytes option for this Bucket.
126+
*
127+
* @return integer
128+
*/
129+
public function getChunkSizeBytes()
130+
{
131+
return $this->options['chunkSizeBytes'];
132+
}
133+
public function getDatabaseName()
134+
{
135+
return $this->databaseName;
136+
}
137+
public function getFilesCollection()
138+
{
139+
return $this->filesCollection;
140+
}
141+
public function getChunksCollection()
142+
{
143+
return $this->chunksCollection;
144+
}
145+
public function find($filter, array $options =[])
146+
{
147+
//add proper validation for the filter and for the options
148+
return $this->filesCollection->find($filter);
149+
}
150+
151+
public function chunkInsert($toUpload) {
152+
$this->chunksCollection->insertOne($toUpload);
153+
}
154+
155+
public function fileInsert($toUpload) {
156+
$this->filesCollection->insertOne($toUpload);
157+
}
158+
159+
public function ensureIndexes()
160+
{
161+
if ($this->ensuredIndexes) {
162+
return;
163+
}
164+
if ( ! $this->isFilesCollectionEmpty()) {
165+
return;
166+
}
167+
$this->ensureFilesIndex();
168+
$this->ensureChunksIndex();
169+
$this->ensuredIndexes = true;
170+
}
171+
172+
private function ensureChunksIndex()
173+
{
174+
foreach ($this->chunksCollection->listIndexes() as $index) {
175+
if ($index->isUnique() && $index->getKey() === ['files_id' => 1, 'n' => 1]) {
176+
return;
177+
}
178+
}
179+
$this->chunksCollection->createIndex(['files_id' => 1, 'n' => 1], ['unique' => true]);
180+
}
181+
182+
private function ensureFilesIndex()
183+
{
184+
foreach ($this->filesCollection->listIndexes() as $index) {
185+
if ($index->getKey() === ['filename' => 1, 'uploadDate' => 1]) {
186+
return;
187+
}
188+
}
189+
$this->filesCollection->createIndex(['filename' => 1, 'uploadDate' => 1]);
190+
}
191+
192+
private function isFilesCollectionEmpty()
193+
{
194+
return null === $this->filesCollection->findOne([], [
195+
'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY),
196+
'projection' => ['_id' => 1],
197+
]);
198+
}
199+
200+
public function delete(ObjectId $id)
201+
{
202+
$options = ['writeConcern' => $this->writeConcern];
203+
$this->chunksCollection->deleteMany(['file_id' => $id], $options);
204+
$this->filesCollection->deleteOne(['_id' => $id], $options);
205+
}
206+
}

‎src/GridFS/BucketReadWriter.php‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
namespace MongoDB\GridFS;
3+
4+
class BucketReadWriter
5+
{
6+
private $bucket;
7+
8+
public function __construct(Bucket $bucket)
9+
{
10+
$this->bucket = $bucket;
11+
}
12+
/**
13+
* Opens a Stream for writing the contents of a file.
14+
*
15+
* @param string $filename file to upload
16+
* @param array $options Stream Options
17+
* @return Stream uploadStream
18+
*/
19+
public function openUploadStream($filename, array $options = [])
20+
{
21+
$options = [
22+
'bucket' => $this->bucket,
23+
'uploadOptions' => $options
24+
];
25+
$context = stream_context_create(['gridfs' => $options]);
26+
return fopen(sprintf('gridfs://%s/%s', $this->bucket->getDatabaseName(), $filename), 'w', false, $context);
27+
}
28+
/**
29+
* Upload a file to this bucket by specifying the source stream file
30+
*
31+
* @param String $filename Filename To Insert
32+
* @param Stream $source Source Stream
33+
* @param array $options Stream Options
34+
* @return ObjectId
35+
*/
36+
public function uploadFromStream($filename, $source, array $options = [])
37+
{
38+
$gridFsStream = new GridFsUpload($this->bucket, $filename, $options);
39+
return $gridFsStream->uploadFromStream($source);
40+
}
41+
}

‎src/GridFS/GridFsStream.php‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
namespace MongoDB\GridFS;
3+
4+
use MongoDB\Collection;
5+
use MongoDB\Exception\RuntimeException;
6+
/**
7+
* GridFsStream holds the configuration for upload or download streams to GridFS
8+
*
9+
* @api
10+
*/
11+
class GridFsStream
12+
{
13+
protected $bucket;
14+
protected $n;
15+
protected $buffer;
16+
protected $file;
17+
/**
18+
* Constructs a GridFsStream
19+
*
20+
* @param \MongoDB\GridFS\Bucket $bucket GridFS Bucket
21+
*/
22+
public function __construct(Bucket $bucket)
23+
{
24+
$this->bucket = $bucket;
25+
$this->n = 0;
26+
$this->buffer = fopen('php://temp', 'w+');
27+
}
28+
}

0 commit comments

Comments
(0)

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