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 b3743b8
Show file tree
Hide file tree
Showing 13 changed files with 143 additions and 36 deletions.
4 changes: 4 additions & 0 deletions docs/demo/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@
"require": {
"recca0120/upload": "dev-master"
}
,
"require-dev": {
"roave/security-advisories": "dev-latest"
}
}
25 changes: 7 additions & 18 deletions docs/demo/upload.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@

use Recca0120\Upload\Dropzone;
use Recca0120\Upload\FileAPI;
use Recca0120\Upload\FilePond;
use Recca0120\Upload\FineUploader;
use Recca0120\Upload\Plupload;
use Recca0120\Upload\Receiver;

include __DIR__.'/vendor/autoload.php';
if (file_exists(__DIR__.'/../../vendor/autoload.php')) {
include __DIR__.'/../../vendor/autoload.php';
} else {
include __DIR__.'/vendor/autoload.php';
}

$config = [
'chunks' => 'temp/chunks',
Expand All @@ -32,23 +37,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
7 changes: 0 additions & 7 deletions src/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,6 @@ abstract class Api implements ApiContract
*/
protected $files;

/**
* $chunkFile.
*
* @var ChunkFileFactory
*/
protected $ChunkFileFactory;

/**
* $config.
*
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);

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->completed($offset)) {
throw new ChunkedResponseException();
}

return $chunkFile->createUploadedFile();
}

private function completed(int $offset): bool
{
$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));
}
}
2 changes: 1 addition & 1 deletion src/UploadServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public function register()
/**
* handle publishes.
*/
protected function handlePublishes()
protected function handlePublishes(): void
{
$this->publishes([
__DIR__.'/../config/upload.php' => config_path('upload.php'),
Expand Down
4 changes: 4 additions & 0 deletions tests/FileAPITest.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ public function testReceiveChunkedFile(): void
self::assertEquals('{}', $response->getContent());
}

/**
* @throws FileNotFoundException
* @throws ResourceOpenException
*/
public function testReceiveChunkedFileWithoutContentRange(): void
{
$this->request->headers->replace([
Expand Down
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): void
{
$reflectedClass = new ReflectionClass($this->request);
$reflection = $reflectedClass->getProperty('content');
$reflection->setAccessible(true);
$reflection->setValue($this->request, $value);
}
}
4 changes: 4 additions & 0 deletions tests/FineUploaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ protected function setUp(): void
$this->api = new FineUploader($this->config, $this->request, $this->files);
}

/**
* @throws FileNotFoundException
* @throws ResourceOpenException
*/
public function testReceiveSingleFile(): void
{
$this->assertSame($this->uploadedFile, $this->api->receive('foo'));
Expand Down
8 changes: 3 additions & 5 deletions tests/ReceiverTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,10 @@ public function testReceiveAndThrowChunkedResponseException(): void
$receiver = new Receiver($api = m::mock(Api::class));
$inputName = 'foo';
$api->allows('receive')->once()->with($inputName)->andThrow(new ChunkedResponseException());
$callback = function () {
};

$this->assertInstanceOf(
Response::class,
$receiver->receive($inputName, function () {
})
);
$this->assertInstanceOf(Response::class, $receiver->receive($inputName, $callback));
}

public function testFactory(): void
Expand Down

0 comments on commit b3743b8

Please sign in to comment.