Skip to content

Commit dd47027

Browse files
authored
Add Plupload driver (#60)
* Add Plupload driver * Re-arrange use
1 parent c0a6302 commit dd47027

File tree

7 files changed

+627
-0
lines changed

7 files changed

+627
-0
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ project at the moment is [tus](https://tus.io/).
3737
- [Blueimp](#blueimp-driver)
3838
- [DropzoneJS](#dropzonejs-driver)
3939
- [Flow.js](#flow-js-driver)
40+
- [Plupload](#plupload-driver)
4041
- [Resumable.js](#resumable-js-driver)
4142
- [simple-uploader.js](#simple-uploader-js-driver)
4243
- [Identifiers](#identifiers)
@@ -152,6 +153,7 @@ Service | Driver name | Chunk
152153
[Blueimp](#blueimp-driver) | `blueimp` | yes | yes
153154
[DropzoneJS](#dropzonejs-driver) | `dropzone` | yes | no
154155
[Flow.js](#flow-js-driver) | `flow-js` | yes | yes
156+
[Plupload](#plupload-driver) | `plupload` | yes | no
155157
[Resumable.js](#resumable-js-driver) | `resumable-js` | yes | yes
156158
[simple-uploader.js](#simple-uploader-js-driver) | `simple-uploader-js` | yes | yes
157159

@@ -177,6 +179,12 @@ This driver handles requests made by the DropzoneJS client library.
177179

178180
This driver handles requests made by the Flow.js client library.
179181

182+
### Plupload driver
183+
184+
[website](https://github.com/moxiecode/plupload)
185+
186+
This driver handles requests made by the Plupload client library.
187+
180188
### Resumable.js driver
181189

182190
[website](http://resumablejs.com/)

examples/plupload.blade.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<!DOCTYPE html>
2+
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1">
6+
7+
<title>Plupload</title>
8+
</head>
9+
<body>
10+
<h1>Plupload</h1>
11+
12+
<div id="container">
13+
<a id="pickfiles" href="javascript:void(0);">[Select files]</a>
14+
<a id="uploadfiles" href="javascript:void(0);">[Upload files]</a>
15+
</div>
16+
17+
<ul id="filelist">
18+
<li>Your browser doesn't have HTML5 support.</li>
19+
</ul>
20+
21+
<script src="//cdn.jsdelivr.net/gh/moxiecode/plupload/js/plupload.full.min.js"></script>
22+
<script>
23+
function getCookieValue(a) {
24+
const b = document.cookie.match('(^|;)\\s*' + a + '\\s*=\\s*([^;]+)');
25+
return b ? b.pop() : '';
26+
}
27+
28+
const uploadUrl = "{{ url('upload') }}";
29+
const uploader = new plupload.Uploader({
30+
browse_button: 'pickfiles',
31+
container: document.getElementById('container'),
32+
url: uploadUrl,
33+
chunk_size: 1024 * 1024,
34+
35+
headers: {'X-XSRF-TOKEN': decodeURIComponent(getCookieValue('XSRF-TOKEN'))},
36+
37+
init: {
38+
PostInit: function () {
39+
document.getElementById('filelist').innerHTML = '';
40+
41+
document.getElementById('uploadfiles').onclick = () => {
42+
uploader.start();
43+
return false;
44+
};
45+
},
46+
47+
FilesAdded: function (up, files) {
48+
plupload.each(files, function (file) {
49+
const node = document.createElement('li');
50+
node.innerHTML = file.name + ' (' + plupload.formatSize(file.size) + ')';
51+
document.getElementById('filelist').append(node);
52+
});
53+
},
54+
}
55+
});
56+
57+
uploader.init();
58+
</script>
59+
</body>
60+
</html>
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<?php
2+
3+
namespace CodingSocks\ChunkUploader\Driver;
4+
5+
use Closure;
6+
use CodingSocks\ChunkUploader\Helper\ChunkHelpers;
7+
use CodingSocks\ChunkUploader\Identifier\Identifier;
8+
use CodingSocks\ChunkUploader\Range\PluploadRange;
9+
use CodingSocks\ChunkUploader\Response\PercentageJsonResponse;
10+
use CodingSocks\ChunkUploader\StorageConfig;
11+
use Illuminate\Http\Request;
12+
use Illuminate\Http\UploadedFile;
13+
use InvalidArgumentException;
14+
use Symfony\Component\HttpFoundation\Response;
15+
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
16+
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
17+
18+
class PluploadUploadDriver extends UploadDriver
19+
{
20+
use ChunkHelpers;
21+
22+
/**
23+
* @var \CodingSocks\ChunkUploader\Identifier\Identifier
24+
*/
25+
private $identifier;
26+
27+
/**
28+
* PluploadUploadDriver constructor.
29+
*
30+
* @param \CodingSocks\ChunkUploader\Identifier\Identifier $identifier
31+
*/
32+
public function __construct(Identifier $identifier)
33+
{
34+
$this->identifier = $identifier;
35+
}
36+
37+
38+
/**
39+
* @inheritDoc
40+
*/
41+
public function handle(Request $request, StorageConfig $config, Closure $fileUploaded = null): Response
42+
{
43+
if ($this->isRequestMethodIn($request, [Request::METHOD_POST])) {
44+
return $this->save($request, $config, $fileUploaded);
45+
}
46+
47+
throw new MethodNotAllowedHttpException([
48+
Request::METHOD_POST,
49+
]);
50+
}
51+
52+
/**
53+
* @param \Illuminate\Http\Request $request
54+
* @param \CodingSocks\ChunkUploader\StorageConfig $config
55+
* @param \Closure|null $fileUploaded
56+
*
57+
* @return mixed
58+
*/
59+
private function save(Request $request, StorageConfig $config, ?Closure $fileUploaded)
60+
{
61+
$file = $request->file('file');
62+
63+
$this->validateUploadedFile($file);
64+
65+
$this->validateChunkRequest($request);
66+
67+
return $this->saveChunk($file, $request, $config, $fileUploaded);
68+
}
69+
70+
/**
71+
* @param \Illuminate\Http\Request $request
72+
*/
73+
private function validateChunkRequest(Request $request): void
74+
{
75+
$request->validate([
76+
'name' => 'required',
77+
'chunk' => 'required|integer',
78+
'chunks' => 'required|integer',
79+
]);
80+
}
81+
82+
/**
83+
* @param \Illuminate\Http\UploadedFile $file
84+
* @param \Illuminate\Http\Request $request
85+
* @param \CodingSocks\ChunkUploader\StorageConfig $config
86+
* @param \Closure|null $fileUploaded
87+
*
88+
* @return \Symfony\Component\HttpFoundation\Response
89+
*/
90+
private function saveChunk(UploadedFile $file, Request $request, StorageConfig $config, Closure $fileUploaded = null): Response
91+
{
92+
try {
93+
$range = new PluploadRange($request);
94+
} catch (InvalidArgumentException $e) {
95+
throw new BadRequestHttpException($e->getMessage(), $e);
96+
}
97+
98+
$uuid = $this->identifier->generateFileIdentifier($range->getTotal(), $file->getClientOriginalName());
99+
100+
$chunks = $this->storeChunk($config, $range, $file, $uuid);
101+
102+
if (!$range->isLast()) {
103+
return new PercentageJsonResponse($range->getPercentage());
104+
}
105+
106+
$targetFilename = $file->hashName();
107+
108+
$path = $this->mergeChunks($config, $chunks, $targetFilename);
109+
110+
if ($config->sweep()) {
111+
$this->deleteChunkDirectory($config, $uuid);
112+
}
113+
114+
$this->triggerFileUploadedEvent($config->getDisk(), $path, $fileUploaded);
115+
116+
return new PercentageJsonResponse($range->getPercentage());
117+
}
118+
}

src/Range/PluploadRange.php

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php
2+
3+
namespace CodingSocks\ChunkUploader\Range;
4+
5+
use Illuminate\Http\Request;
6+
use InvalidArgumentException;
7+
8+
class PluploadRange implements Range
9+
{
10+
private static $CHUNK_NUMBER_PARAMETER_NAME = 'chunk';
11+
private static $TOTAL_CHUNK_NUMBER_PARAMETER_NAME = 'chunks';
12+
13+
/**
14+
* @var float
15+
*/
16+
protected $current;
17+
18+
/**
19+
* @var float
20+
*/
21+
protected $total;
22+
23+
/**
24+
* NgFileUploadRange constructor.
25+
*
26+
* @param \Illuminate\Http\Request|\Symfony\Component\HttpFoundation\ParameterBag $request
27+
*/
28+
public function __construct($request)
29+
{
30+
if ($request instanceof Request) {
31+
$request = $request->request;
32+
}
33+
34+
$this->current = (float) $request->get(self::$CHUNK_NUMBER_PARAMETER_NAME);
35+
$this->total = (float) $request->get(self::$TOTAL_CHUNK_NUMBER_PARAMETER_NAME);
36+
37+
if ($this->current < 0) {
38+
throw new InvalidArgumentException(
39+
sprintf('`%s` must be greater than or equal to zero', self::$CHUNK_NUMBER_PARAMETER_NAME)
40+
);
41+
}
42+
if ($this->total < 1) {
43+
throw new InvalidArgumentException(
44+
sprintf('`%s` must be greater than zero', self::$TOTAL_CHUNK_NUMBER_PARAMETER_NAME)
45+
);
46+
}
47+
if ($this->current >= $this->total) {
48+
throw new InvalidArgumentException(
49+
sprintf('`%s` must be less than `%s`', self::$CHUNK_NUMBER_PARAMETER_NAME, self::$TOTAL_CHUNK_NUMBER_PARAMETER_NAME)
50+
);
51+
}
52+
}
53+
54+
/**
55+
* {@inheritDoc}
56+
*/
57+
public function getStart(): float
58+
{
59+
return $this->current;
60+
}
61+
62+
/**
63+
* {@inheritDoc}
64+
*/
65+
public function getEnd(): float
66+
{
67+
return $this->current + 1;
68+
}
69+
70+
/**
71+
* {@inheritDoc}
72+
*/
73+
public function getTotal(): float
74+
{
75+
return $this->total;
76+
}
77+
78+
/**
79+
* {@inheritDoc}
80+
*/
81+
public function isFirst(): bool
82+
{
83+
return $this->current === 0.0;
84+
}
85+
86+
/**
87+
* {@inheritDoc}
88+
*/
89+
public function isLast(): bool
90+
{
91+
return $this->current >= ($this->total - 1);
92+
}
93+
94+
/**
95+
* @return float
96+
*/
97+
public function getPercentage(): float
98+
{
99+
return floor(($this->current + 1) / $this->total * 100);
100+
}
101+
}

src/UploadManager.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use CodingSocks\ChunkUploader\Driver\DropzoneUploadDriver;
77
use CodingSocks\ChunkUploader\Driver\FlowJsUploadDriver;
88
use CodingSocks\ChunkUploader\Driver\MonolithUploadDriver;
9+
use CodingSocks\ChunkUploader\Driver\PluploadUploadDriver;
910
use CodingSocks\ChunkUploader\Driver\ResumableJsUploadDriver;
1011
use CodingSocks\ChunkUploader\Driver\SimpleUploaderJsUploadDriver;
1112
use Illuminate\Support\Manager;
@@ -35,6 +36,14 @@ public function createFlowJsDriver()
3536
return new FlowJsUploadDriver($this->app['config']['chunk-uploader.resumable-js']);
3637
}
3738

39+
public function createPluploadDriver()
40+
{
41+
/** @var \Illuminate\Support\Manager $identityManager */
42+
$identityManager = $this->app['chunk-uploader.identity-manager'];
43+
44+
return new PluploadUploadDriver($identityManager->driver());
45+
}
46+
3847
public function createResumableJsDriver()
3948
{
4049
return new ResumableJsUploadDriver($this->app['config']['chunk-uploader.resumable-js']);

0 commit comments

Comments
 (0)