Laravel version update
Laravel version update
This commit is contained in:
67
vendor/flowjs/flow-php-server/src/Flow/Autoloader.php
vendored
Normal file
67
vendor/flowjs/flow-php-server/src/Flow/Autoloader.php
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Flow;
|
||||
|
||||
class Autoloader
|
||||
{
|
||||
/**
|
||||
* Directory path
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $dir;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string|null $dir
|
||||
*/
|
||||
public function __construct($dir = null)
|
||||
{
|
||||
if (is_null($dir)) {
|
||||
$dir = __DIR__.'/..';
|
||||
}
|
||||
|
||||
$this->dir = $dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return directory path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDir()
|
||||
{
|
||||
return $this->dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @param string|null $dir
|
||||
*/
|
||||
public static function register($dir = null)
|
||||
{
|
||||
ini_set('unserialize_callback_func', 'spl_autoload_call');
|
||||
spl_autoload_register(array(new self($dir), 'autoload'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles autoloading of classes
|
||||
*
|
||||
* @param string $class A class name
|
||||
*
|
||||
* @return boolean Returns true if the class has been loaded
|
||||
*/
|
||||
public function autoload($class)
|
||||
{
|
||||
if (0 !== strpos($class, 'Flow')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (file_exists($file = $this->dir.'/'.str_replace('\\', '/', $class).'.php')) {
|
||||
require $file;
|
||||
}
|
||||
}
|
||||
}
|
54
vendor/flowjs/flow-php-server/src/Flow/Basic.php
vendored
Normal file
54
vendor/flowjs/flow-php-server/src/Flow/Basic.php
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Flow;
|
||||
|
||||
/**
|
||||
* Class Basic
|
||||
*
|
||||
* Example for handling basic uploads
|
||||
*
|
||||
* @package Flow
|
||||
*/
|
||||
class Basic
|
||||
{
|
||||
/**
|
||||
* @param string $destination where to save file
|
||||
* @param string|ConfigInterface $config
|
||||
* @param RequestInterface $request optional
|
||||
* @return bool
|
||||
*/
|
||||
public static function save($destination, $config, RequestInterface $request = null)
|
||||
{
|
||||
if (!$config instanceof ConfigInterface) {
|
||||
$config = new Config(array(
|
||||
'tempDir' => $config,
|
||||
));
|
||||
}
|
||||
|
||||
$file = new File($config, $request);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
if ($file->checkChunk()) {
|
||||
header("HTTP/1.1 200 Ok");
|
||||
} else {
|
||||
// The 204 response MUST NOT include a message-body, and thus is always terminated by the first empty line after the header fields.
|
||||
header("HTTP/1.1 204 No Content");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if ($file->validateChunk()) {
|
||||
$file->saveChunk();
|
||||
} else {
|
||||
// error, invalid chunk upload request, retry
|
||||
header("HTTP/1.1 400 Bad Request");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($file->validateFile() && $file->save($destination)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
115
vendor/flowjs/flow-php-server/src/Flow/Config.php
vendored
Normal file
115
vendor/flowjs/flow-php-server/src/Flow/Config.php
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
namespace Flow;
|
||||
|
||||
class Config implements ConfigInterface
|
||||
{
|
||||
/**
|
||||
* Config
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* Controller
|
||||
*
|
||||
* @param array $config
|
||||
*/
|
||||
public function __construct($config = array())
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set path to temporary directory for chunks storage
|
||||
*
|
||||
* @param $path
|
||||
*/
|
||||
public function setTempDir($path)
|
||||
{
|
||||
$this->config['tempDir'] = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get path to temporary directory for chunks storage
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTempDir()
|
||||
{
|
||||
return isset($this->config['tempDir']) ? $this->config['tempDir'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set chunk identifier
|
||||
*
|
||||
* @param callable $callback
|
||||
*/
|
||||
public function setHashNameCallback($callback)
|
||||
{
|
||||
$this->config['hashNameCallback'] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate chunk identifier
|
||||
*
|
||||
* @return callable
|
||||
*/
|
||||
public function getHashNameCallback()
|
||||
{
|
||||
return isset($this->config['hashNameCallback']) ? $this->config['hashNameCallback'] : '\Flow\Config::hashNameCallback';
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to pre-process chunk
|
||||
*
|
||||
* @param callable $callback
|
||||
*/
|
||||
public function setPreprocessCallback($callback)
|
||||
{
|
||||
$this->config['preprocessCallback'] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to pre-process chunk
|
||||
*
|
||||
* @return callable|null
|
||||
*/
|
||||
public function getPreprocessCallback()
|
||||
{
|
||||
return isset($this->config['preprocessCallback']) ? $this->config['preprocessCallback'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete chunks on save
|
||||
*
|
||||
* @param bool $delete
|
||||
*/
|
||||
public function setDeleteChunksOnSave($delete)
|
||||
{
|
||||
$this->config['deleteChunksOnSave'] = $delete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete chunks on save
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getDeleteChunksOnSave()
|
||||
{
|
||||
return isset($this->config['deleteChunksOnSave']) ? $this->config['deleteChunksOnSave'] : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate chunk identifier
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function hashNameCallback(RequestInterface $request)
|
||||
{
|
||||
return sha1($request->getIdentifier());
|
||||
}
|
||||
}
|
48
vendor/flowjs/flow-php-server/src/Flow/ConfigInterface.php
vendored
Normal file
48
vendor/flowjs/flow-php-server/src/Flow/ConfigInterface.php
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Flow;
|
||||
|
||||
interface ConfigInterface
|
||||
{
|
||||
/**
|
||||
* Get path to temporary directory for chunks storage
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTempDir();
|
||||
|
||||
/**
|
||||
* Generate chunk identifier
|
||||
*
|
||||
* @return callable
|
||||
*/
|
||||
public function getHashNameCallback();
|
||||
|
||||
/**
|
||||
* Callback to pre-process chunk
|
||||
*
|
||||
* @param callable $callback
|
||||
*/
|
||||
public function setPreprocessCallback($callback);
|
||||
|
||||
/**
|
||||
* Callback to preprocess chunk
|
||||
*
|
||||
* @return callable|null
|
||||
*/
|
||||
public function getPreprocessCallback();
|
||||
|
||||
/**
|
||||
* Delete chunks on save
|
||||
*
|
||||
* @param bool $delete
|
||||
*/
|
||||
public function setDeleteChunksOnSave($delete);
|
||||
|
||||
/**
|
||||
* Delete chunks on save
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getDeleteChunksOnSave();
|
||||
}
|
233
vendor/flowjs/flow-php-server/src/Flow/File.php
vendored
Normal file
233
vendor/flowjs/flow-php-server/src/Flow/File.php
vendored
Normal file
@@ -0,0 +1,233 @@
|
||||
<?php
|
||||
|
||||
namespace Flow;
|
||||
|
||||
class File
|
||||
{
|
||||
/**
|
||||
* @var RequestInterface
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* @var ConfigInterface
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* File hashed unique identifier
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $identifier;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param ConfigInterface $config
|
||||
* @param RequestInterface $request
|
||||
*/
|
||||
public function __construct(ConfigInterface $config, RequestInterface $request = null)
|
||||
{
|
||||
$this->config = $config;
|
||||
|
||||
if ($request === null) {
|
||||
$request = new Request();
|
||||
}
|
||||
|
||||
$this->request = $request;
|
||||
$this->identifier = call_user_func($this->config->getHashNameCallback(), $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file identifier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return chunk path
|
||||
*
|
||||
* @param int $index
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getChunkPath($index)
|
||||
{
|
||||
return $this->config->getTempDir().DIRECTORY_SEPARATOR.basename($this->identifier).'_'. (int) $index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if chunk exist
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function checkChunk()
|
||||
{
|
||||
return file_exists($this->getChunkPath($this->request->getCurrentChunkNumber()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate file request
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function validateChunk()
|
||||
{
|
||||
$file = $this->request->getFile();
|
||||
|
||||
if (!$file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($file['tmp_name']) || !isset($file['size']) || !isset($file['error'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->request->getCurrentChunkSize() != $file['size']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($file['error'] !== UPLOAD_ERR_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save chunk
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function saveChunk()
|
||||
{
|
||||
$file = $this->request->getFile();
|
||||
|
||||
return $this->_move_uploaded_file($file['tmp_name'], $this->getChunkPath($this->request->getCurrentChunkNumber()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if file upload is complete
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function validateFile()
|
||||
{
|
||||
$totalChunks = $this->request->getTotalChunks();
|
||||
$totalChunksSize = 0;
|
||||
|
||||
for ($i = $totalChunks; $i >= 1; $i--) {
|
||||
$file = $this->getChunkPath($i);
|
||||
if (!file_exists($file)) {
|
||||
return false;
|
||||
}
|
||||
$totalChunksSize += filesize($file);
|
||||
}
|
||||
|
||||
return $this->request->getTotalSize() == $totalChunksSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge all chunks to single file
|
||||
*
|
||||
* @param string $destination final file location
|
||||
*
|
||||
*
|
||||
* @throws FileLockException
|
||||
* @throws FileOpenException
|
||||
* @throws \Exception
|
||||
*
|
||||
* @return bool indicates if file was saved
|
||||
*/
|
||||
public function save($destination)
|
||||
{
|
||||
$fh = fopen($destination, 'wb');
|
||||
if (!$fh) {
|
||||
throw new FileOpenException('failed to open destination file: '.$destination);
|
||||
}
|
||||
|
||||
if (!flock($fh, LOCK_EX | LOCK_NB, $blocked)) {
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($blocked) {
|
||||
// Concurrent request has requested a lock.
|
||||
// File is being processed at the moment.
|
||||
// Warning: lock is not checked in windows.
|
||||
return false;
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
throw new FileLockException('failed to lock file: '.$destination);
|
||||
}
|
||||
|
||||
$totalChunks = $this->request->getTotalChunks();
|
||||
|
||||
try {
|
||||
$preProcessChunk = $this->config->getPreprocessCallback();
|
||||
|
||||
for ($i = 1; $i <= $totalChunks; $i++) {
|
||||
$file = $this->getChunkPath($i);
|
||||
$chunk = fopen($file, "rb");
|
||||
|
||||
if (!$chunk) {
|
||||
throw new FileOpenException('failed to open chunk: '.$file);
|
||||
}
|
||||
|
||||
if ($preProcessChunk !== null) {
|
||||
call_user_func($preProcessChunk, $chunk);
|
||||
}
|
||||
|
||||
stream_copy_to_stream($chunk, $fh);
|
||||
fclose($chunk);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
flock($fh, LOCK_UN);
|
||||
fclose($fh);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if ($this->config->getDeleteChunksOnSave()) {
|
||||
$this->deleteChunks();
|
||||
}
|
||||
|
||||
flock($fh, LOCK_UN);
|
||||
fclose($fh);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete chunks dir
|
||||
*/
|
||||
public function deleteChunks()
|
||||
{
|
||||
$totalChunks = $this->request->getTotalChunks();
|
||||
|
||||
for ($i = 1; $i <= $totalChunks; $i++) {
|
||||
$path = $this->getChunkPath($i);
|
||||
if (file_exists($path)) {
|
||||
unlink($path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used only for testing
|
||||
*
|
||||
* @private
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param string $filePath
|
||||
* @param string $destinationPath
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function _move_uploaded_file($filePath, $destinationPath)
|
||||
{
|
||||
return move_uploaded_file($filePath, $destinationPath);
|
||||
}
|
||||
}
|
7
vendor/flowjs/flow-php-server/src/Flow/FileLockException.php
vendored
Normal file
7
vendor/flowjs/flow-php-server/src/Flow/FileLockException.php
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Flow;
|
||||
|
||||
class FileLockException extends \Exception
|
||||
{
|
||||
}
|
7
vendor/flowjs/flow-php-server/src/Flow/FileOpenException.php
vendored
Normal file
7
vendor/flowjs/flow-php-server/src/Flow/FileOpenException.php
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Flow;
|
||||
|
||||
class FileOpenException extends \Exception
|
||||
{
|
||||
}
|
39
vendor/flowjs/flow-php-server/src/Flow/FustyRequest.php
vendored
Normal file
39
vendor/flowjs/flow-php-server/src/Flow/FustyRequest.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Flow;
|
||||
|
||||
/**
|
||||
* Class FustyRequest
|
||||
*
|
||||
* Imitates single file request as a single chunk file upload
|
||||
*
|
||||
* @package Flow
|
||||
*/
|
||||
class FustyRequest extends Request
|
||||
{
|
||||
private $isFusty = false;
|
||||
|
||||
public function __construct($params = null, $file = null)
|
||||
{
|
||||
parent::__construct($params, $file);
|
||||
|
||||
$this->isFusty = $this->getTotalSize() === null && $this->getFileName() && $this->getFile();
|
||||
|
||||
if ($this->isFusty) {
|
||||
$this->params['flowTotalSize'] = isset($this->file['size']) ? $this->file['size'] : 0;
|
||||
$this->params['flowTotalChunks'] = 1;
|
||||
$this->params['flowChunkNumber'] = 1;
|
||||
$this->params['flowChunkSize'] = $this->params['flowTotalSize'];
|
||||
$this->params['flowCurrentChunkSize'] = $this->params['flowTotalSize'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if request is formed by fusty flow
|
||||
* @return bool
|
||||
*/
|
||||
public function isFustyFlowRequest()
|
||||
{
|
||||
return $this->isFusty;
|
||||
}
|
||||
}
|
31
vendor/flowjs/flow-php-server/src/Flow/Mongo/MongoConfig.php
vendored
Normal file
31
vendor/flowjs/flow-php-server/src/Flow/Mongo/MongoConfig.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Flow\Mongo;
|
||||
|
||||
use Flow\Config;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class MongoConfig extends Config implements MongoConfigInterface
|
||||
{
|
||||
private $gridFs;
|
||||
|
||||
/**
|
||||
* @param \MongoGridFS $gridFS storage of the upload (and chunks)
|
||||
*/
|
||||
function __construct(\MongoGridFS $gridFS)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->gridFs = $gridFS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return \MongoGridFS
|
||||
*/
|
||||
public function getGridFs()
|
||||
{
|
||||
return $this->gridFs;
|
||||
}
|
||||
}
|
18
vendor/flowjs/flow-php-server/src/Flow/Mongo/MongoConfigInterface.php
vendored
Normal file
18
vendor/flowjs/flow-php-server/src/Flow/Mongo/MongoConfigInterface.php
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Flow\Mongo;
|
||||
|
||||
use Flow\ConfigInterface;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
interface MongoConfigInterface extends ConfigInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @return \MongoGridFS
|
||||
*/
|
||||
public function getGridFs();
|
||||
|
||||
}
|
181
vendor/flowjs/flow-php-server/src/Flow/Mongo/MongoFile.php
vendored
Normal file
181
vendor/flowjs/flow-php-server/src/Flow/Mongo/MongoFile.php
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
<?php
|
||||
|
||||
namespace Flow\Mongo;
|
||||
|
||||
use Flow\File;
|
||||
use Flow\Request;
|
||||
use Flow\RequestInterface;
|
||||
|
||||
|
||||
/**
|
||||
* Notes:
|
||||
*
|
||||
* - One should ensure indices on the gridfs collection on the property 'flowIdentifier'.
|
||||
* - Chunk preprocessor not supported (must not modify chunks size)!
|
||||
* - Must use 'forceChunkSize=true' on client side.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class MongoFile extends File
|
||||
{
|
||||
private $uploadGridFsFile;
|
||||
|
||||
/**
|
||||
* @var MongoConfigInterface
|
||||
*/
|
||||
private $config;
|
||||
|
||||
function __construct(MongoConfigInterface $config, RequestInterface $request = null)
|
||||
{
|
||||
if ($request === null) {
|
||||
$request = new Request();
|
||||
}
|
||||
parent::__construct($config, $request);
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* return array
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $index int|string 1-based
|
||||
* @return bool
|
||||
*/
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Save chunk
|
||||
* @return bool
|
||||
* @throws \Exception if upload size is invalid or some other unexpected error occurred.
|
||||
*/
|
||||
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); // \MongoBinData::GENERIC is not defined for older mongo drivers
|
||||
$this->config->getGridFs()->chunks->findAndModify($chunkQuery, $chunk, [], ['upsert' => true]);
|
||||
unlink($file['tmp_name']);
|
||||
|
||||
$this->ensureIndices();
|
||||
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
// try to remove a possibly (partly) stored chunk:
|
||||
if (isset($chunkQuery)) {
|
||||
$this->config->getGridFs()->chunks->remove($chunkQuery);
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function validateFile()
|
||||
{
|
||||
$totalChunks = $this->request->getTotalChunks();
|
||||
|
||||
for ($i = 1; $i <= $totalChunks; $i++) {
|
||||
if (!$this->chunkExists($i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Merge all chunks to single file
|
||||
* @param $metadata array additional metadata for final file
|
||||
* @return \MongoId|bool of saved file or false if file was already saved
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function saveToGridFs($metadata = null)
|
||||
{
|
||||
$file = $this->getGridFsFile();
|
||||
$file['flowStatus'] = 'finished';
|
||||
$file['metadata'] = $metadata;
|
||||
$result = $this->config->getGridFs()->findAndModify($this->getGridFsFileQuery(), $file);
|
||||
// on second invocation no more file can be found, as the flowStatus changed:
|
||||
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()
|
||||
{
|
||||
// nothing to do, as chunks are directly part of the final file
|
||||
}
|
||||
|
||||
public function ensureIndices()
|
||||
{
|
||||
$chunksCollection = $this->config->getGridFs()->chunks;
|
||||
$indexKeys = ['files_id' => 1, 'n' => 1];
|
||||
$indexOptions = ['unique' => true, 'background' => true];
|
||||
if(method_exists($chunksCollection, 'createIndex')) { // only available for PECL mongo >= 1.5.0
|
||||
$chunksCollection->createIndex($indexKeys, $indexOptions);
|
||||
} else {
|
||||
$chunksCollection->ensureIndex($indexKeys, $indexOptions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getGridFsFileQuery()
|
||||
{
|
||||
return [
|
||||
'flowIdentifier' => $this->request->getIdentifier(),
|
||||
'flowStatus' => 'uploading',
|
||||
'filename' => $this->request->getFileName(),
|
||||
'chunkSize' => intval($this->request->getDefaultChunkSize()),
|
||||
'length' => intval($this->request->getTotalSize())
|
||||
];
|
||||
}
|
||||
}
|
31
vendor/flowjs/flow-php-server/src/Flow/Mongo/MongoUploader.php
vendored
Normal file
31
vendor/flowjs/flow-php-server/src/Flow/Mongo/MongoUploader.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Flow\Mongo;
|
||||
|
||||
use Flow\FileOpenException;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class MongoUploader
|
||||
{
|
||||
/**
|
||||
* Delete chunks older than expiration time.
|
||||
*
|
||||
* @param \MongoGridFS $gridFs
|
||||
* @param int $expirationTime seconds
|
||||
*
|
||||
* @throws FileOpenException
|
||||
*/
|
||||
public static function pruneChunks($gridFs, $expirationTime = 172800)
|
||||
{
|
||||
$result = $gridFs->remove([
|
||||
'flowUpdated' => ['$lt' => new \MongoDate(time() - $expirationTime)],
|
||||
'flowStatus' => 'uploading'
|
||||
]);
|
||||
|
||||
if (!$result) {
|
||||
throw new FileOpenException("Could not remove chunks!");
|
||||
}
|
||||
}
|
||||
}
|
50
vendor/flowjs/flow-php-server/src/Flow/Mongo/README.md
vendored
Normal file
50
vendor/flowjs/flow-php-server/src/Flow/Mongo/README.md
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
Usage
|
||||
--------------
|
||||
|
||||
* Must use 'forceChunkSize=true' on client side.
|
||||
* Chunk preprocessor not supported.
|
||||
* One should ensure indices on the gridfs collection on the property 'flowIdentifier'.
|
||||
|
||||
Besides the points above, the usage is analogous to the 'normal' flow-php:
|
||||
|
||||
```php
|
||||
$config = new \Flow\Mongo\MongoConfig($yourGridFs);
|
||||
$file = new \Flow\Mongo\MongoFile($config);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
|
||||
if ($file->checkChunk()) {
|
||||
header("HTTP/1.1 200 Ok");
|
||||
} else {
|
||||
header("HTTP/1.1 204 No Content");
|
||||
return ;
|
||||
}
|
||||
} else {
|
||||
if ($file->validateChunk()) {
|
||||
$file->saveChunk();
|
||||
} else {
|
||||
// error, invalid chunk upload request, retry
|
||||
header("HTTP/1.1 400 Bad Request");
|
||||
return ;
|
||||
}
|
||||
}
|
||||
if ($file->validateFile()) {
|
||||
// File upload was completed
|
||||
$id = $file->saveToGridFs(['your metadata'=>'value']);
|
||||
if($id) {
|
||||
//do custom post processing here, $id is the MongoId of the gridfs file
|
||||
}
|
||||
} else {
|
||||
// This is not a final chunk, continue to upload
|
||||
}
|
||||
```
|
||||
|
||||
Delete unfinished files
|
||||
-----------------------
|
||||
|
||||
For this you should setup cron, which would check each chunk upload time.
|
||||
If chunk is uploaded long time ago, then chunk should be deleted.
|
||||
|
||||
Helper method for checking this:
|
||||
```php
|
||||
\Flow\Mongo\MongoUploader::pruneChunks($yourGridFs);
|
||||
```
|
152
vendor/flowjs/flow-php-server/src/Flow/Request.php
vendored
Normal file
152
vendor/flowjs/flow-php-server/src/Flow/Request.php
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
namespace Flow;
|
||||
|
||||
class Request implements RequestInterface
|
||||
{
|
||||
/**
|
||||
* Request parameters
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $params;
|
||||
|
||||
/**
|
||||
* File
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $file;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array|null $params
|
||||
* @param array|null $file
|
||||
*/
|
||||
public function __construct($params = null, $file = null)
|
||||
{
|
||||
if ($params === null) {
|
||||
$params = $_REQUEST;
|
||||
}
|
||||
|
||||
if ($file === null && isset($_FILES['file'])) {
|
||||
$file = $_FILES['file'];
|
||||
}
|
||||
|
||||
$this->params = $params;
|
||||
$this->file = $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get parameter value
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return string|int|null
|
||||
*/
|
||||
public function getParam($name)
|
||||
{
|
||||
return isset($this->params[$name]) ? $this->params[$name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get uploaded file name
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getFileName()
|
||||
{
|
||||
return $this->getParam('flowFilename');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get total file size in bytes
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function getTotalSize()
|
||||
{
|
||||
return $this->getParam('flowTotalSize');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file unique identifier
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getIdentifier()
|
||||
{
|
||||
return $this->getParam('flowIdentifier');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file relative path
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getRelativePath()
|
||||
{
|
||||
return $this->getParam('flowRelativePath');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get total chunks number
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function getTotalChunks()
|
||||
{
|
||||
return $this->getParam('flowTotalChunks');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default chunk size
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function getDefaultChunkSize()
|
||||
{
|
||||
return $this->getParam('flowChunkSize');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current uploaded chunk number, starts with 1
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function getCurrentChunkNumber()
|
||||
{
|
||||
return $this->getParam('flowChunkNumber');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current uploaded chunk size
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function getCurrentChunkSize()
|
||||
{
|
||||
return $this->getParam('flowCurrentChunkSize');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return $_FILES request
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function getFile()
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if request is formed by fusty flow
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isFustyFlowRequest()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
76
vendor/flowjs/flow-php-server/src/Flow/RequestInterface.php
vendored
Normal file
76
vendor/flowjs/flow-php-server/src/Flow/RequestInterface.php
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Flow;
|
||||
|
||||
interface RequestInterface
|
||||
{
|
||||
/**
|
||||
* Get uploaded file name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFileName();
|
||||
|
||||
/**
|
||||
* Get total file size in bytes
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTotalSize();
|
||||
|
||||
/**
|
||||
* Get file unique identifier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier();
|
||||
|
||||
/**
|
||||
* Get file relative path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRelativePath();
|
||||
|
||||
/**
|
||||
* Get total chunks number
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTotalChunks();
|
||||
|
||||
/**
|
||||
* Get default chunk size
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getDefaultChunkSize();
|
||||
|
||||
/**
|
||||
* Get current uploaded chunk number, starts with 1
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getCurrentChunkNumber();
|
||||
|
||||
/**
|
||||
* Get current uploaded chunk size
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getCurrentChunkSize();
|
||||
|
||||
/**
|
||||
* Return $_FILES request
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function getFile();
|
||||
|
||||
/**
|
||||
* Checks if request is formed by fusty flow
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isFustyFlowRequest();
|
||||
}
|
41
vendor/flowjs/flow-php-server/src/Flow/Uploader.php
vendored
Normal file
41
vendor/flowjs/flow-php-server/src/Flow/Uploader.php
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Flow;
|
||||
|
||||
class Uploader
|
||||
{
|
||||
/**
|
||||
* Delete chunks older than expiration time.
|
||||
*
|
||||
* @param string $chunksFolder
|
||||
* @param int $expirationTime seconds
|
||||
*
|
||||
* @throws FileOpenException
|
||||
*/
|
||||
public static function pruneChunks($chunksFolder, $expirationTime = 172800)
|
||||
{
|
||||
$handle = opendir($chunksFolder);
|
||||
|
||||
if (!$handle) {
|
||||
throw new FileOpenException('failed to open folder: '.$chunksFolder);
|
||||
}
|
||||
|
||||
while (false !== ($entry = readdir($handle))) {
|
||||
if ($entry == "." || $entry == ".." || $entry == ".gitignore") {
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = $chunksFolder.DIRECTORY_SEPARATOR.$entry;
|
||||
|
||||
if (is_dir($path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (time() - filemtime($path) > $expirationTime) {
|
||||
unlink($path);
|
||||
}
|
||||
}
|
||||
|
||||
closedir($handle);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user