Skip to content

Commit e862316

Browse files
author
Will Banfield
committed
implementation of GridFS upload
1 parent d36e9bd commit e862316

File tree

5 files changed

+286
-211
lines changed

5 files changed

+286
-211
lines changed

src/GridFS/Bucket.php

Lines changed: 60 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
*/
1919
class Bucket
2020
{
21-
private $manager;
2221
private $databaseName;
2322
private $options;
2423
private $filesCollection;
@@ -46,7 +45,7 @@ class Bucket
4645
*/
4746
public function __construct(Manager $manager, $databaseName, array $options = [])
4847
{
49-
$collectionOpts = array();
48+
$collectionOptions = array();
5049
$options += [
5150
'bucketName' => 'fs',
5251
'chunkSizeBytes' => 261120,
@@ -58,32 +57,31 @@ public function __construct(Manager $manager, $databaseName, array $options = []
5857
throw new InvalidArgumentTypeException('"chunkSizeBytes" option', $options['chunkSizeBytes'], 'integer');
5958
}
6059
if (isset($options['readPreference'])) {
61-
if (! $options['readPreference'] instanceof ReadPreference) {
62-
throw new InvalidArgumentTypeException('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
63-
} else {
64-
$collectionOpts['readPreference'] = $options['readPreference'];
65-
}
60+
if (! $options['readPreference'] instanceof ReadPreference) {
61+
throw new InvalidArgumentTypeException('"readPreference" option', $options['readPreference'], 'MongoDB\Driver\ReadPreference');
62+
} else {
63+
$collectionOptions['readPreference'] = $options['readPreference'];
64+
}
6665
}
6766
if (isset($options['writeConcern'])) {
68-
if (! $options['writeConcern'] instanceof WriteConcern) {
69-
throw new InvalidArgumentTypeException('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
70-
} else {
71-
$collectionOpts['writeConcern'] = $options['writeConcern'];
72-
}
67+
if (! $options['writeConcern'] instanceof WriteConcern) {
68+
throw new InvalidArgumentTypeException('"writeConcern" option', $options['writeConcern'], 'MongoDB\Driver\WriteConcern');
69+
} else {
70+
$collectionOptions['writeConcern'] = $options['writeConcern'];
71+
}
7372
}
74-
$this->manager = $manager;
7573
$this->databaseName = (string) $databaseName;
7674
$this->options = $options;
7775

7876
$this->filesCollection = new Collection(
7977
$manager,
8078
sprintf('%s.%s.files', $this->databaseName, $options['bucketName']),
81-
$collectionOpts
79+
$collectionOptions
8280
);
8381
$this->chunksCollection = new Collection(
8482
$manager,
8583
sprintf('%s.%s.chunks', $this->databaseName, $options['bucketName']),
86-
$collectionOpts
84+
$collectionOptions
8785
);
8886
}
8987
/**
@@ -94,35 +92,34 @@ public function __construct(Manager $manager, $databaseName, array $options = []
9492
*/
9593
public function openDownloadStream(ObjectId $id)
9694
{
97-
fopen("gridfs://$this->databaseName/$id", "r");
95+
fopen('gridfs://$this->databaseName/$id', 'r');
9896
}
99-
/**
100-
* Downloads the contents of the stored file specified by id and writes
101-
* the contents to the destination Stream.
102-
* @param ObjectId $id
103-
* @param Stream destination
104-
*/
105-
public function downloadToStream(ObjectId $id, $destination)
106-
{
107-
$result = $this->filesCollection->findOne(["_id" => $id]);
108-
if($result == null) {
109-
return;
110-
}
111-
if($result->length == 0){
112-
return;
113-
}
114-
115-
$n=0;
116-
$results = $this->chunksCollection->find(["files_id" => $result->_id]);
117-
foreach($results as $chunk) {
118-
if($chunk->n != $n){
119-
return;
120-
}
121-
fwrite($destination, $chunk->data);
122-
$n++;
123-
}
124-
}
97+
/**
98+
* Downloads the contents of the stored file specified by id and writes
99+
* the contents to the destination Stream.
100+
* @param ObjectId $id GridFS File Id
101+
* @param Stream $destination Destination Stream
102+
*/
103+
public function downloadToStream(ObjectId $id, $destination)
104+
{
105+
$result = $this->filesCollection->findOne(['_id' => $id]);
106+
if ($result == null) {
107+
return;
108+
}
109+
if ($result->length == 0){
110+
return;
111+
}
125112

113+
$n=0;
114+
$results = $this->chunksCollection->find(['files_id' => $result->_id]);
115+
foreach ($results as $chunk) {
116+
if ($chunk->n != $n) {
117+
return;
118+
}
119+
fwrite($destination, $chunk->data);
120+
$n++;
121+
}
122+
}
126123
/**
127124
* Return the chunkSizeBytes option for this Bucket.
128125
*
@@ -135,84 +132,39 @@ public function getChunkSizeBytes()
135132
/**
136133
* Opens a Stream for writing the contents of a file.
137134
*
138-
* @param string $filename file to up
139-
* @param array $options options for the stream
140-
* @return Stream uploadStream what stream to upload from
135+
* @param string $filename file to upload
136+
* @param array $options Stream Options
137+
* @return Stream uploadStream
141138
*/
142139
public function openUploadStream($filename, array $options = [])
143140
{
144-
return fopen("gridfs://$this->databaseName/$filename", "w");
141+
$this->ensureIndexes();
142+
$options = [
143+
'filesCollection' => $this->filesCollection,
144+
'chunksCollection' => $this->chunksCollection,
145+
'chunkSizeBytes' => $this->getChunkSizeBytes()
146+
];
147+
$context = stream_context_create(['gridfs' => $options]);
148+
return fopen('gridfs://$this->databaseName/$filename', 'w', false, $context);
145149
}
146150
/**
147151
* Upload a file to this bucket by specifying the source stream file
148152
*
149-
* @param String fileName
150-
* @param Stream source
151-
* @param array Options
153+
* @param String $filename Filename To Insert
154+
* @param Stream $source Source Stream
155+
* @param array $options Stream Options
152156
* @return ObjectId
153157
*/
154158

155-
public function uploadFromStream($filename, $source, array $options = []) {
156-
$id = \MongoDB\BSON\ObjectId();
157-
$ctx = hash_init('md5');
158-
159-
$file_options = [];
160-
if (isset($options['contentType'])) {
161-
if(is_string($options['contentType'])) {
162-
$file_options['contentType'] = $options['contentType'];
163-
} else {
164-
throw new InvalidArgumentTypeException('"contentType" option', $options['contentType'], 'string');
165-
}
166-
}
167-
if (isset($options['aliases'])) {
168-
if(isStringArray($options['aliases'])) {
169-
$file_options['aliases'] = $options['aliases'];
170-
} else {
171-
throw new InvalidArgumentTypeException('"aliases" option', $options['aliases'], 'array of strings');
172-
}
173-
}
174-
175-
if (isset($options['metadata'])) {
176-
if(is_array($options['metadata']) || is_object($options['metadata'])) {
177-
$file_options['metadata'] = $options['metadata'];
178-
} else {
179-
throw new InvalidArgumentTypeException('"metadata" option', $options['metadata'], 'object or array');
180-
}
181-
}
182-
159+
public function uploadFromStream($filename, $source, array $options = [])
160+
{
183161
$this->ensureIndexes();
184-
185-
$n=0;
186-
while ($data = fread($source, $this->getChunkSizeBytes())) {
187-
$toUpload = ["files_id" => $id, "n" => $n, "data" => $data];
188-
$this->chunksCollection->insertOne($toUpload);
189-
hash_update($ctx, $data);
190-
$n++;
191-
}
192-
$uploadDate = time();
193-
$md5 = hash_final($ctx, true);
194-
$file = ["chunkSize" => $this->getChunkSizeBytes(), "filename" => $filename, "uploadDate" => $uploadDate,
195-
"md5" => $md5, "length" => $this->n];
196-
$file = array_merge($file, $file_options);
197-
$doc = $this->filesCollection->insertOne($file);
198-
return $id;
199-
}
200-
201-
private function isStringArray($input) {
202-
if (!is_array($input)){
203-
return false;
204-
}
205-
foreach($input as $item) {
206-
if (!is_string($item)) {
207-
return false;
208-
}
209-
}
210-
return true;
162+
$gridFsStream = new GridFsUpload($this->filesCollection, $this->chunksCollection, $this->getChunkSizeBytes(), $filename, $options);
163+
return $gridFsStream->uploadFromStream($source);
211164
}
212165

213166
private function ensureIndexes()
214167
{
215-
// Indexes should only be ensured once before the first write operation
216168
if ($this->ensuredIndexes) {
217169
return;
218170
}
@@ -250,9 +202,9 @@ private function isFilesCollectionEmpty()
250202
}
251203
public function delete(ObjectId $id)
252204
{
253-
$options = array("writeConcern" => $this->writeConcern);
254-
$this->chunksCollection->deleteMany(["file_id" => $id], $options);
205+
$options = array('writeConcern' => $this->writeConcern);
206+
$this->chunksCollection->deleteMany(['file_id' => $id], $options);
255207

256-
$this->filesCollection->deleteOne(["_id" => $id], $options);
208+
$this->filesCollection->deleteOne(['_id' => $id], $options);
257209
}
258210
}

src/GridFS/GridFsStream.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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 $chunkSizeBytes;
14+
protected $filesCollection;
15+
protected $chunksCollection;
16+
protected $n;
17+
protected $buffer;
18+
protected $file;
19+
/**
20+
* Constructs a GridFsStream
21+
*
22+
* @param \MongoDB\Collection $filesCollection GridFS files Collection
23+
* @param \MongoDB\Collection $chunksCollection GridFS chunks Collection
24+
* @param int32 $chunkSizeBytes Size of chunks
25+
*/
26+
public function __construct(\MongoDB\Collection $filesCollection,\MongoDB\Collection $chunksCollection, $chunkSizeBytes)
27+
{
28+
$this->chunkSizeBytes = $chunkSizeBytes;
29+
$this->filesCollection = $filesCollection;
30+
$this->chunksCollection = $chunksCollection;
31+
$this->n = 0;
32+
$this->buffer = fopen('php://temp', 'w+');
33+
}
34+
}

0 commit comments

Comments
 (0)