View source
<?php
namespace Flow\Mongo;
use Flow\File;
use Flow\Request;
use Flow\RequestInterface;
class MongoFile extends File {
private $uploadGridFsFile;
private $config;
function __construct(MongoConfigInterface $config, RequestInterface $request = null) {
if ($request === null) {
$request = new Request();
}
parent::__construct($config, $request);
$this->config = $config;
}
protected function getGridFsFile() {
if (!$this->uploadGridFsFile) {
$gridFsFileQuery = $this
->getGridFsFileQuery();
$changed = $gridFsFileQuery;
$changed['flowUpdated'] = new \MongoDate();
$this->uploadGridFsFile = $this->config
->getGridFs()
->findAndModify($gridFsFileQuery, $changed, null, [
'upsert' => true,
'new' => true,
]);
}
return $this->uploadGridFsFile;
}
public function chunkExists($index) {
return $this->config
->getGridFs()->chunks
->find([
'files_id' => $this
->getGridFsFile()['_id'],
'n' => intval($index) - 1,
])
->limit(1)
->hasNext();
}
public function checkChunk() {
return $this
->chunkExists($this->request
->getCurrentChunkNumber());
}
public function saveChunk() {
try {
$file = $this->request
->getFile();
$chunkQuery = [
'files_id' => $this
->getGridFsFile()['_id'],
'n' => intval($this->request
->getCurrentChunkNumber()) - 1,
];
$chunk = $chunkQuery;
$data = file_get_contents($file['tmp_name']);
$actualChunkSize = strlen($data);
if ($actualChunkSize > $this->request
->getDefaultChunkSize() || $actualChunkSize < $this->request
->getDefaultChunkSize() && $this->request
->getCurrentChunkNumber() != $this->request
->getTotalChunks()) {
throw new \Exception("Invalid upload! (size: {$actualChunkSize})");
}
$chunk['data'] = new \MongoBinData($data, 0);
$this->config
->getGridFs()->chunks
->findAndModify($chunkQuery, $chunk, [], [
'upsert' => true,
]);
unlink($file['tmp_name']);
$this
->ensureIndices();
return true;
} catch (\Exception $e) {
if (isset($chunkQuery)) {
$this->config
->getGridFs()->chunks
->remove($chunkQuery);
}
throw $e;
}
}
public function validateFile() {
$totalChunks = $this->request
->getTotalChunks();
for ($i = 1; $i <= $totalChunks; $i++) {
if (!$this
->chunkExists($i)) {
return false;
}
}
return true;
}
public function saveToGridFs($metadata = null) {
$file = $this
->getGridFsFile();
$file['flowStatus'] = 'finished';
$file['metadata'] = $metadata;
$result = $this->config
->getGridFs()
->findAndModify($this
->getGridFsFileQuery(), $file);
if (is_null($result)) {
return false;
}
else {
return $file['_id'];
}
}
public function save($destination) {
throw new \Exception("Must not use 'save' on MongoFile - use 'saveToGridFs'!");
}
public function deleteChunks() {
}
public function ensureIndices() {
$chunksCollection = $this->config
->getGridFs()->chunks;
$indexKeys = [
'files_id' => 1,
'n' => 1,
];
$indexOptions = [
'unique' => true,
'background' => true,
];
if (method_exists($chunksCollection, 'createIndex')) {
$chunksCollection
->createIndex($indexKeys, $indexOptions);
}
else {
$chunksCollection
->ensureIndex($indexKeys, $indexOptions);
}
}
protected function getGridFsFileQuery() {
return [
'flowIdentifier' => $this->request
->getIdentifier(),
'flowStatus' => 'uploading',
'filename' => $this->request
->getFileName(),
'chunkSize' => intval($this->request
->getDefaultChunkSize()),
'length' => intval($this->request
->getTotalSize()),
];
}
}