Skip to content

Commit

Permalink
file-pond
Browse files Browse the repository at this point in the history
  • Loading branch information
recca0120 committed Apr 29, 2023
1 parent 42f69c6 commit 9cd734a
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 23 deletions.
2 changes: 1 addition & 1 deletion docs/demo/composer.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"require": {
"recca0120/upload": "dev-master"
"recca0120/upload": "dev-file-pond"
}
}
19 changes: 2 additions & 17 deletions docs/demo/upload.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use Recca0120\Upload\Dropzone;
use Recca0120\Upload\FileAPI;
use Recca0120\Upload\FilePond;
use Recca0120\Upload\FineUploader;
use Recca0120\Upload\Plupload;
use Recca0120\Upload\Receiver;
Expand Down Expand Up @@ -32,23 +33,7 @@
break;

case 'file-pond':
if (! empty($_POST['file'])) {
echo '12345.png';
// var_dump($_SERVER['HTTP_UPLOAD_LENGTH']);
exit;
}
if ($_GET['patch']) {
var_dump($_SERVER['HTTP_UPLOAD_NAME']);
var_dump($_SERVER['HTTP_UPLOAD_LENGTH']);
var_dump($_SERVER['HTTP_UPLOAD_OFFSET']);
var_dump($_SERVER['HTTP_CONTENT_TYPE']);
$mode = $_SERVER['HTTP_UPLOAD_OFFSET'] === '0' ? 'wb+' : 'ab+';
$fp = fopen(__DIR__.'/test.png', $mode);
fseek($fp, $_SERVER['HTTP_UPLOAD_OFFSET']);
fwrite($fp, file_get_contents('php://input'));
fclose($fp);
}
exit;
$receiver = new Receiver(new FilePond($config));
break;

default:
Expand Down
6 changes: 2 additions & 4 deletions src/ChunkFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@ public function __construct(
*/
public function appendStream($source, int $offset = 0): ChunkFile
{
$chunkFile = $this->chunkFile();
$this->files->appendStream($chunkFile, $source, $offset);
$this->files->appendStream($this->chunkFile(), $source, $offset);

return $this;
}
Expand All @@ -86,8 +85,7 @@ public function appendStream($source, int $offset = 0): ChunkFile
*/
public function appendFile($source, int $index = 0): ChunkFile
{
$chunkFile = $this->chunkFile().'.'.$index;
$this->files->appendStream($chunkFile, $source, 0);
$this->files->appendStream($this->chunkFile().'.'.$index, $source, 0);

return $this;
}
Expand Down
33 changes: 33 additions & 0 deletions src/FilePond.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,46 @@

namespace Recca0120\Upload;

use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Recca0120\Upload\Exceptions\ChunkedResponseException;
use Recca0120\Upload\Exceptions\ResourceOpenException;

class FilePond extends Api
{
/**
* @throws ResourceOpenException
* @throws FileNotFoundException
*/
public function receive(string $name)
{
$uploadedFile = $this->request->file($name);
if (! empty($uploadedFile)) {
return $uploadedFile;
}

if (! $this->request->headers->has('Upload-Name')) {
throw new ChunkedResponseException(md5(uniqid('file-pond-', true)));
}

$originalName = $this->request->header('Upload-Name');
$uuid = $this->request->get('patch');
$offset = (int) $this->request->header('Upload-Offset');

$chunkFile = $this->createChunkFile($originalName, $uuid);
$chunkFile->appendStream($this->request->getContent(true), $offset);

if (! $this->isCompleted($offset)) {
throw new ChunkedResponseException();
}

return $chunkFile->createUploadedFile();
}

private function isCompleted(int $offset)
{
$size = (int) $this->request->header('Upload-Length');
$length = (int) $this->request->header('Content-Length');

return $size === $offset + $length;
}
}
3 changes: 2 additions & 1 deletion src/FineUploader.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ public function receive(string $name)

if ($completed === false) {
$chunkFile->appendFile($file->getRealPath(), $partindex);
throw new ChunkedResponseException(['success' => true, 'uuid' => $uuid], []);

throw new ChunkedResponseException(['success' => true, 'uuid' => $uuid]);
}

return $chunkFile->createUploadedFile($totalparts);
Expand Down
1 change: 1 addition & 0 deletions src/Receiver.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public static function factory(array $config = [], string $class = FileAPI::clas
'fileapi' => FileAPI::class,
'fineuploader' => FineUploader::class,
'plupload' => Plupload::class,
'filepond' => FilePond::class,
];

$class = Arr::get($lookup, strtolower($class), $class);
Expand Down
5 changes: 5 additions & 0 deletions src/UploadManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,9 @@ protected function createPluploadDriver(): Receiver
{
return new Receiver(new Plupload($this->container['config']['upload'], $this->request, $this->files));
}

protected function createFilePond(): Receiver
{
return new Receiver(new FilePond($this->container['config']['upload'], $this->request, $this->files));
}
}
77 changes: 77 additions & 0 deletions tests/FilePondTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

namespace Recca0120\Upload\Tests;

use Illuminate\Contracts\Filesystem\FileNotFoundException;
use Recca0120\Upload\Exceptions\ChunkedResponseException;
use Recca0120\Upload\Exceptions\ResourceOpenException;
use Recca0120\Upload\FilePond;
use ReflectionClass;
use ReflectionException;

class FilePondTest extends TestCase
{
Expand All @@ -11,10 +16,82 @@ protected function setUp(): void
parent::setUp();

$this->api = new FilePond($this->config, $this->request, $this->files);
$this->request->files->remove('foo');
}

public function testReceiveSingleFile(): void
{
$this->request->files->replace(['foo' => $this->uploadedFile]);

$this->assertSame($this->uploadedFile, $this->api->receive('foo'));
}

public function testReceiveChunkedFileAndThrowUniqIdChunkedResponseException(): void
{
$this->expectException(ChunkedResponseException::class);
$this->expectExceptionMessageMatches('/\w+/');

$this->request->replace(['file' => '{}']);
$this->request->headers->replace(['Upload-Length' => $this->uploadedFile->getSize()]);
$this->api->receive('foo');
}

/**
* @throws ReflectionException
* @throws ResourceOpenException
* @throws FileNotFoundException
*/
public function testReceiveChunkedFile(): void
{
$this->request->setMethod('patch');
$this->request->replace(['patch' => $this->uuid]);
$content = $this->uploadedFile->getContent();

$size = $this->uploadedFile->getSize();
$name = $this->uploadedFile->getClientOriginalName();

$length = 10;
$loop = 2;
$offset = 0;
for ($i = 0; $i < $loop; $i++) {
$offset = $i * $length;
$this->setProperty(substr($content, $offset, $length));
$this->request->headers->replace([
'Upload-Length' => $size,
'Upload-Name' => $name,
'Upload-Offset' => $offset,
'Content-Length' => $length,
]);

try {
$this->api->receive('foo');
} catch (ChunkedResponseException $e) {

}
}

$offset *= $loop;
$this->setProperty(substr($content, $offset));
$this->request->headers->replace([
'Upload-Length' => $size,
'Upload-Name' => $name,
'Upload-Offset' => $offset,
'Content-Length' => $size - $offset,
]);

$uploadedFile = $this->api->receive('foo');
self::assertTrue($uploadedFile->isValid());
self::assertEquals($size, $uploadedFile->getSize());
}

/**
* @throws ReflectionException
*/
private function setProperty($value)
{
$reflectedClass = new ReflectionClass($this->request);
$reflection = $reflectedClass->getProperty('content');
$reflection->setAccessible(true);
$reflection->setValue($this->request, $value);
}
}

0 comments on commit 9cd734a

Please sign in to comment.