From 6163aab8823f029bc811352f8384c4c9204c6e4d Mon Sep 17 00:00:00 2001 From: Abilogos Date: Fri, 24 Nov 2023 15:47:32 +0300 Subject: [PATCH 01/14] replicate black-bit changes - return status code --- composer.json | 8 ++++++-- readme.md | 21 +++++++++++++++++++-- src/Network/SimpleResponse.php | 15 ++++++++++++--- src/Resumable.php | 5 +++-- 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index db97502..ec7e1f7 100644 --- a/composer.json +++ b/composer.json @@ -1,10 +1,14 @@ { - "name": "dilab/resumable.php", - "description": "PHP package for Resumable.js", + "name": "abilogos/resumable.php", + "description": "PHP package for Resumable.js for yii framework forked from dilab/resumable.php", "authors": [ { "name": "xu ding", "email": "thedilab@gmail.com" + }, + { + "name": "Ali Hakami", + "email": "dev.abi.log@gmail.com" } ], "require": { diff --git a/readme.md b/readme.md index d3e3462..ef626fc 100644 --- a/readme.md +++ b/readme.md @@ -1,11 +1,16 @@ # PHP backend for resumable.js +This is a fork from [dilab/resumable.php](https://github.com/dilab/resumable.php) + +inspired by [black-bits/resumable.js-laravel-backend](https://github.com/black-bits/resumable.js-laravel-backend) + +reworked for integerating with Yii 2.0 framework ## Installation To install, use composer: -``` composer require dilab/resumable.php ``` +``` composer require abilogos/resumable.php ``` ## How to use @@ -25,7 +30,19 @@ $response = new SimpleResponse(); $resumable = new Resumable($request, $response); $resumable->tempFolder = 'tmps'; $resumable->uploadFolder = 'uploads'; -$resumable->process(); +$status = $resumable->process(); + +$response->statusCode = in_array($status, [200,201,204]) ? $status : 404; + +return match ($status){ + 200 => ['message' => 'OK'], // Uploading of chunk is complete. + 201 => [ + 'message' => 'File uploaded', + 'file' => $params['resumableFilename'] + ],// Uploading of whole file is complete. + 204 => ['message' => 'Chunk not found'],//TODO: will work in resumable:0.1.4 after update monolog + default => ['message' => 'An error occurred'] //status => 404 + }; ``` diff --git a/src/Network/SimpleResponse.php b/src/Network/SimpleResponse.php index 715d8a2..04a71a4 100644 --- a/src/Network/SimpleResponse.php +++ b/src/Network/SimpleResponse.php @@ -12,11 +12,20 @@ class SimpleResponse implements Response public function header($statusCode) { if (200==$statusCode) { - return header($_SERVER["SERVER_PROTOCOL"]." 200 Ok"); + header($_SERVER["SERVER_PROTOCOL"]." 200 Ok"); + return 200; + } else if (201==$statusCode) { + header($_SERVER["SERVER_PROTOCOL"]." 201 Accepted"); + return 201; // upload complete + } else if (204==$statusCode) { + header($_SERVER["SERVER_PROTOCOL"]." 204 No Content"); + return 204; // chunk not found } else if (404==$statusCode) { - return header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found"); + header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found"); + return 404; } - return header($_SERVER["SERVER_PROTOCOL"]." 204 No Content"); + header($_SERVER["SERVER_PROTOCOL"]." 404 No Content"); + return 404; } } diff --git a/src/Resumable.php b/src/Resumable.php index f2ae54c..6a863b6 100644 --- a/src/Resumable.php +++ b/src/Resumable.php @@ -81,9 +81,9 @@ public function process() { if (!empty($this->resumableParams())) { if (!empty($this->request->file())) { - $this->handleChunk(); + return $this->handleChunk(); } else { - $this->handleTestChunk(); + return $this->handleTestChunk(); } } } @@ -200,6 +200,7 @@ public function handleChunk() if ($this->isFileUploadComplete($filename, $identifier, $chunkSize, $totalSize)) { $this->isUploadComplete = true; $this->createFileAndDeleteTmp($identifier, $filename); + return $this->response->header(201); } return $this->response->header(200); From f159c7fb8193ebfbecd95ea0b246ab2b2358ada5 Mon Sep 17 00:00:00 2001 From: Abilogos Date: Fri, 24 Nov 2023 15:50:33 +0300 Subject: [PATCH 02/14] support for monolog 3 has been added --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index ec7e1f7..f91d295 100644 --- a/composer.json +++ b/composer.json @@ -12,9 +12,9 @@ } ], "require": { - "php": ">=5.3.0", + "php": ">=8.1.0", "cakephp/filesystem": "^3.0", - "monolog/monolog": "^1.17" + "monolog/monolog": "^3.0" }, "require-dev": { "phpunit/phpunit": "~4.0" From e88a03bd81d7eea6e4d9f6e32714e73651ec3e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C7=83=D1=88=C9=92=CA=9E=C9=92H=20=C7=83=C7=80=C9=84?= Date: Fri, 24 Nov 2023 16:37:12 +0330 Subject: [PATCH 03/14] Update composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index f91d295..de1bc8b 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "abilogos/resumable.php", + "name": "dilab/resumable.php", "description": "PHP package for Resumable.js for yii framework forked from dilab/resumable.php", "authors": [ { From 9a286b646cb40ec924044bed9e5cdd5d21eeaa45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C7=83=D1=88=C9=92=CA=9E=C9=92H=20=C7=83=C7=80=C9=84?= Date: Fri, 24 Nov 2023 16:42:49 +0330 Subject: [PATCH 04/14] Update composer.json change the monolog version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index de1bc8b..9a71b3a 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ "require": { "php": ">=8.1.0", "cakephp/filesystem": "^3.0", - "monolog/monolog": "^3.0" + "monolog/monolog": "^2.0" }, "require-dev": { "phpunit/phpunit": "~4.0" From 47556703481d1ca5c20b6d41a0642f05fcbc224e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C7=83=D1=88=C9=92=CA=9E=C9=92H=20=C7=83=C7=80=C9=84?= Date: Wed, 29 Nov 2023 12:32:44 +0330 Subject: [PATCH 05/14] Update composer.json --- composer.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/composer.json b/composer.json index 9a71b3a..1404a31 100644 --- a/composer.json +++ b/composer.json @@ -1,14 +1,10 @@ { "name": "dilab/resumable.php", - "description": "PHP package for Resumable.js for yii framework forked from dilab/resumable.php", + "description": "PHP package for Resumable.js", "authors": [ { "name": "xu ding", "email": "thedilab@gmail.com" - }, - { - "name": "Ali Hakami", - "email": "dev.abi.log@gmail.com" } ], "require": { From 8679f55545ae96cd7eea8f12d4bbfff83cf0073c Mon Sep 17 00:00:00 2001 From: Abilogos Date: Thu, 30 Nov 2023 12:03:40 +0300 Subject: [PATCH 06/14] added instanceId as constructor param in order to isolate uploads and prevent name collission. it can be set to user_id to prevent collission --- src/Resumable.php | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/Resumable.php b/src/Resumable.php index 6a863b6..deb86d0 100644 --- a/src/Resumable.php +++ b/src/Resumable.php @@ -24,6 +24,8 @@ class Resumable protected $response; + protected $instanceId; + protected $params; protected $chunkFile; @@ -50,10 +52,11 @@ class Resumable const WITHOUT_EXTENSION = true; - public function __construct(Request $request, Response $response) + public function __construct(Request $request, Response $response, string|null $instanceId = null) { $this->request = $request; $this->response = $response; + $this->instanceId = $instanceId; $this->log = new Logger('debug'); $this->log->pushHandler(new StreamHandler('debug.log', Logger::DEBUG)); @@ -222,7 +225,12 @@ private function createFileAndDeleteTmp($identifier, $filename) } // replace filename reference by the final file - $this->filepath = $this->uploadFolder . DIRECTORY_SEPARATOR . $finalFilename; + $this->filepath = $this->uploadFolder . DIRECTORY_SEPARATOR; + if (!empty($this->instanceId)) { + $this->filepath .= $this->instanceId . DIRECTORY_SEPARATOR; + } + $this->filepath .= $finalFilename; + $this->extension = $this->findExtension($this->filepath); if ($this->createFileFromChunks($chunkFiles, $this->filepath) && $this->deleteTmpFolder) { @@ -272,9 +280,14 @@ public function isChunkUploaded($identifier, $filename, $chunkNumber) public function tmpChunkDir($identifier) { - $tmpChunkDir = $this->tempFolder . DIRECTORY_SEPARATOR . $identifier; + $tmpChunkDir = $this->tempFolder. DIRECTORY_SEPARATOR; + if (!empty($this->instanceId)){ + $tmpChunkDir .= $this->instanceId . DIRECTORY_SEPARATOR; + } + $tmpChunkDir .= $identifier; if (!file_exists($tmpChunkDir)) { - mkdir($tmpChunkDir); + umask(0); + mkdir($tmpChunkDir, 0775, true); } return $tmpChunkDir; } @@ -300,6 +313,11 @@ public function createFileFromChunks($chunkFiles, $destFile) natsort($chunkFiles); + if (!empty($this->instanceId) && !file_exists(dirname($destFile)) ) { + umask(0); + mkdir(dirname($destFile), 0775, true); + } + $handle = $this->getExclusiveFileHandle($destFile); if (!$handle) { return false; From 58784881084e6da0703830a4c74bac15f7e9f70f Mon Sep 17 00:00:00 2001 From: Abilogos Date: Fri, 1 Dec 2023 13:32:12 +0300 Subject: [PATCH 07/14] Bugfix: when a file chunk has been uploaded. it didn't report the finished state. --- src/Resumable.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Resumable.php b/src/Resumable.php index deb86d0..b9a1d08 100644 --- a/src/Resumable.php +++ b/src/Resumable.php @@ -177,10 +177,17 @@ public function handleTestChunk() $identifier = $this->resumableParam($this->resumableOption['identifier']); $filename = $this->resumableParam($this->resumableOption['filename']); $chunkNumber = $this->resumableParam($this->resumableOption['chunkNumber']); + $chunkSize = $this->resumableParam($this->resumableOption['chunkSize']); + $totalSize = $this->resumableParam($this->resumableOption['totalSize']); if (!$this->isChunkUploaded($identifier, $filename, $chunkNumber)) { return $this->response->header(204); } else { + if ($this->isFileUploadComplete($filename, $identifier, $chunkSize, $totalSize)) { + $this->isUploadComplete = true; + $this->createFileAndDeleteTmp($identifier, $filename); + return $this->response->header(201); + } return $this->response->header(200); } From cce1703c14d2b2fb2ae2c2c721cd5bd9d7c21d5a Mon Sep 17 00:00:00 2001 From: Abilogos Date: Wed, 6 Dec 2023 17:01:28 +0300 Subject: [PATCH 08/14] fix problem with race condition in directory creation --- src/Resumable.php | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/Resumable.php b/src/Resumable.php index b9a1d08..3444259 100644 --- a/src/Resumable.php +++ b/src/Resumable.php @@ -292,13 +292,33 @@ public function tmpChunkDir($identifier) $tmpChunkDir .= $this->instanceId . DIRECTORY_SEPARATOR; } $tmpChunkDir .= $identifier; - if (!file_exists($tmpChunkDir)) { - umask(0); - mkdir($tmpChunkDir, 0775, true); - } + $this->ensureDirExists($tmpChunkDir); return $tmpChunkDir; } + /** + * make directory if it doesn't exists (Immune against the race condition) + * + * + * since the resuamble is usually used with simultaneously uploads, + * this sometimes resulted in directory creation btween the *is_dir* check + * and *mkdir* then following race condition. + * in this setup it will shut down the mkdir error + * then try to check if directory is created after that + * + * @param string $path the directoryPath to ensure + * @return void + * @throws \Exception + */ + private function ensureDirExists($path) + { + umask(0); + if ( is_dir($path) || @mkdir($path, 0775, true) || is_dir($path)) { + return; + } + throw new \Exception("could not mkdir $path"); + } + public function tmpChunkFilename($filename, $chunkNumber) { return $filename . '.' . str_pad($chunkNumber, 4, 0, STR_PAD_LEFT); @@ -320,9 +340,8 @@ public function createFileFromChunks($chunkFiles, $destFile) natsort($chunkFiles); - if (!empty($this->instanceId) && !file_exists(dirname($destFile)) ) { - umask(0); - mkdir(dirname($destFile), 0775, true); + if (!empty($this->instanceId)) { + $this->ensureDirExists(dirname($destFile)); } $handle = $this->getExclusiveFileHandle($destFile); From 3b10d472e3713341d56398777e6c8f1639db70fa Mon Sep 17 00:00:00 2001 From: Abilogos Date: Wed, 6 Dec 2023 17:02:42 +0300 Subject: [PATCH 09/14] fix bug regarding cakephp TMP not defined on upload pause --- src/Resumable.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Resumable.php b/src/Resumable.php index 3444259..c03e622 100644 --- a/src/Resumable.php +++ b/src/Resumable.php @@ -364,6 +364,9 @@ public function createFileFromChunks($chunkFiles, $destFile) public function moveUploadedFile($file, $destFile) { + //workaround cakephp error regarding: TMP not defined + define("TMP",sys_get_temp_dir()); + $file = new File($file); if ($file->exists()) { return $file->copy($destFile); From a27ac7b6eab9af46252d2858e252713355ca9a26 Mon Sep 17 00:00:00 2001 From: Abilogos Date: Thu, 7 Dec 2023 16:10:45 +0300 Subject: [PATCH 10/14] add new examples to readme --- readme.md | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/readme.md b/readme.md index ef626fc..ce08d66 100644 --- a/readme.md +++ b/readme.md @@ -1,16 +1,10 @@ # PHP backend for resumable.js -This is a fork from [dilab/resumable.php](https://github.com/dilab/resumable.php) - -inspired by [black-bits/resumable.js-laravel-backend](https://github.com/black-bits/resumable.js-laravel-backend) - -reworked for integerating with Yii 2.0 framework - ## Installation To install, use composer: -``` composer require abilogos/resumable.php ``` +``` composer require dilab/resumable.php ``` ## How to use @@ -26,21 +20,21 @@ use Dilab\Resumable; $request = new SimpleRequest(); $response = new SimpleResponse(); +// optional instanceId to seperate uploads from diffrent users like if two users want to upload untitled.jpg there would be no conflict anymore +$instanceId = session_id(); -$resumable = new Resumable($request, $response); +$resumable = new Resumable($request, $response, $instanceId); $resumable->tempFolder = 'tmps'; $resumable->uploadFolder = 'uploads'; $status = $resumable->process(); -$response->statusCode = in_array($status, [200,201,204]) ? $status : 404; - return match ($status){ 200 => ['message' => 'OK'], // Uploading of chunk is complete. 201 => [ 'message' => 'File uploaded', - 'file' => $params['resumableFilename'] + 'file' => $_REQUEST['resumableFilename'] ],// Uploading of whole file is complete. - 204 => ['message' => 'Chunk not found'],//TODO: will work in resumable:0.1.4 after update monolog + 204 => ['message' => 'Chunk not found'], default => ['message' => 'An error occurred'] //status => 404 }; From 5172968603afe4c60ffaeba89d754c2ed7220056 Mon Sep 17 00:00:00 2001 From: Abilogos Date: Thu, 14 Dec 2023 13:27:21 +0300 Subject: [PATCH 11/14] bugfix: wrong assumption about the last chunk --- src/Resumable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Resumable.php b/src/Resumable.php index c03e622..d76d5b4 100644 --- a/src/Resumable.php +++ b/src/Resumable.php @@ -271,7 +271,7 @@ public function isFileUploadComplete($filename, $identifier, $chunkSize, $totalS return false; } $numOfChunks = intval($totalSize / $chunkSize) + ($totalSize % $chunkSize == 0 ? 0 : 1); - for ($i = 1; $i < $numOfChunks; $i++) { + for ($i = 1; $i <= $numOfChunks; $i++) { if (!$this->isChunkUploaded($identifier, $filename, $i)) { return false; } From 0b4ca456782642a48ab72532605b9ab66163ba04 Mon Sep 17 00:00:00 2001 From: Abilogos Date: Thu, 14 Dec 2023 13:27:47 +0300 Subject: [PATCH 12/14] refactor SimpleResponse --- src/Network/SimpleResponse.php | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/Network/SimpleResponse.php b/src/Network/SimpleResponse.php index 04a71a4..5d37b96 100644 --- a/src/Network/SimpleResponse.php +++ b/src/Network/SimpleResponse.php @@ -11,21 +11,14 @@ class SimpleResponse implements Response */ public function header($statusCode) { - if (200==$statusCode) { - header($_SERVER["SERVER_PROTOCOL"]." 200 Ok"); - return 200; - } else if (201==$statusCode) { - header($_SERVER["SERVER_PROTOCOL"]." 201 Accepted"); - return 201; // upload complete - } else if (204==$statusCode) { - header($_SERVER["SERVER_PROTOCOL"]." 204 No Content"); - return 204; // chunk not found - } else if (404==$statusCode) { - header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found"); - return 404; + if($statusCode >= 500) { + $statusCode = 204; } - header($_SERVER["SERVER_PROTOCOL"]." 404 No Content"); - return 404; + if (!in_array($statusCode, [200,201,204,404])) { + $statusCode = 404; + } + http_response_code($statusCode); + return $statusCode; } } From 988948f3228025fdcb676e1812aee0837c87a7bb Mon Sep 17 00:00:00 2001 From: Abilogos Date: Thu, 14 Dec 2023 13:30:15 +0300 Subject: [PATCH 13/14] update phpunit to version 10 --- .gitignore | 4 ++- composer.json | 2 +- phpunit.xml | 24 +++++---------- test/src/Network/SimpleRequestTest.php | 6 ++-- test/src/Network/SimpleResponseTest.php | 20 ++++++------- test/src/ResumableTest.php | 39 +++++++++++++------------ 6 files changed, 44 insertions(+), 51 deletions(-) diff --git a/.gitignore b/.gitignore index c105493..7a1e76a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ vendor/* composer.lock -.idea \ No newline at end of file +.idea +.phpunit.cache/* +.phpunit.*.cache \ No newline at end of file diff --git a/composer.json b/composer.json index 1404a31..b67d234 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "monolog/monolog": "^2.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "phpunit/phpunit": "~10.0" }, "license": "MIT", "autoload": { diff --git a/phpunit.xml b/phpunit.xml index 9447c87..851d307 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,18 +1,8 @@ - - - - ./test/ - - - \ No newline at end of file + + + + ./test/ + + + diff --git a/test/src/Network/SimpleRequestTest.php b/test/src/Network/SimpleRequestTest.php index 9fa3301..e6d8843 100644 --- a/test/src/Network/SimpleRequestTest.php +++ b/test/src/Network/SimpleRequestTest.php @@ -8,14 +8,14 @@ * @package Dilab\Network * @property $request Request */ -class SimpleRequestTest extends \PHPUnit_Framework_TestCase +class SimpleRequestTest extends \PHPUnit\Framework\TestCase { - protected function setUp() + protected function setUp() : void { $this->request = new SimpleRequest(); } - public function tearDown() + public function tearDown() : void { unset($this->request); parent::tearDown(); diff --git a/test/src/Network/SimpleResponseTest.php b/test/src/Network/SimpleResponseTest.php index 8772214..d567c4d 100644 --- a/test/src/Network/SimpleResponseTest.php +++ b/test/src/Network/SimpleResponseTest.php @@ -8,28 +8,28 @@ * @package Dilab\Network * @property $response Response */ -class SimpleResponseTest extends \PHPUnit_Framework_TestCase +class SimpleResponseTest extends \PHPUnit\Framework\TestCase { - protected function setUp() + protected function setUp() : void { $this->response = new SimpleResponse(); } - public function tearDown() + public function tearDown() : void { unset($this->response); parent::tearDown(); } - public function headerProvider() + public static function headerProvider() { - return array( - array(404,404), - array(204,204), - array(200,200), - array(500,204), - ); + return [ + [404,404], + [204,204], + [200,200], + [500,204], + ]; } /** diff --git a/test/src/ResumableTest.php b/test/src/ResumableTest.php index 635dedc..4afe706 100644 --- a/test/src/ResumableTest.php +++ b/test/src/ResumableTest.php @@ -12,13 +12,13 @@ * @property $request Request * @property $response Response */ -class ResumbableTest extends \PHPUnit_Framework_TestCase +class ResumableTest extends \PHPUnit\Framework\TestCase { public $resumbable; protected $provider; - protected function setUp() + protected function setUp() : void { $this->request = $this->getMockBuilder('Dilab\Network\SimpleRequest') ->getMock(); @@ -27,7 +27,7 @@ protected function setUp() ->getMock(); } - public function tearDown() + public function tearDown() : void { unset($this->request); unset($this->response); @@ -45,21 +45,21 @@ public function testProcessHandleChunk() 'resumableRelativePath'=> 'upload', ); - $this->request->method('is')->will($this->returnValue(true)); + $this->request->method('is')->willReturn(true); $this->request->method('file') - ->will($this->returnValue(array( + ->willReturn([ 'name'=> 'mock.png', - 'tmp_name'=> 'test/files/mock.png.003', + 'tmp_name'=> 'test/files/mock.png.0003', 'error'=> 0, 'size'=> 27000, - ))); + ]); $this->request->method('data')->willReturn($resumableParams); $this->resumbable = $this->getMockBuilder('Dilab\Resumable') ->setConstructorArgs(array($this->request,$this->response)) - ->setMethods(array('handleChunk')) + ->onlyMethods(array('handleChunk')) ->getMock(); $this->resumbable->expects($this->once()) @@ -80,15 +80,15 @@ public function testProcessHandleTestChunk() 'resumableRelativePath'=> 'upload', ); - $this->request->method('is')->will($this->returnValue(true)); + $this->request->method('is')->willReturn(true); - $this->request->method('file')->will($this->returnValue(array())); + $this->request->method('file')->willReturn([]); $this->request->method('data')->willReturn($resumableParams); $this->resumbable = $this->getMockBuilder('Dilab\Resumable') ->setConstructorArgs(array($this->request,$this->response)) - ->setMethods(array('handleTestChunk')) + ->onlyMethods(array('handleTestChunk')) ->getMock(); $this->resumbable->expects($this->once()) @@ -101,12 +101,12 @@ public function testProcessHandleTestChunk() public function testHandleTestChunk() { $this->request->method('is') - ->will($this->returnValue(true)); + ->willReturn(true); $this->request->method('data') ->willReturn(array( 'resumableChunkNumber'=> 1, - 'resumableTotalChunks'=> 600, + 'resumableTotalSize'=> 600, 'resumableChunkSize'=> 200, 'resumableIdentifier'=> 'identifier', 'resumableFilename'=> 'mock.png', @@ -125,7 +125,8 @@ public function testHandleTestChunk() public function testHandleChunk() { $resumableParams = array( 'resumableChunkNumber'=> 3, - 'resumableTotalChunks'=> 600, + // 'resumableTotalChunks'=> 600, + 'resumableTotalSize'=> 600, 'resumableChunkSize'=> 200, 'resumableIdentifier'=> 'identifier', 'resumableFilename'=> 'mock.png', @@ -134,7 +135,7 @@ public function testHandleChunk() { $this->request->method('is') - ->will($this->returnValue(true)); + ->willReturn(true); $this->request->method('data') ->willReturn($resumableParams); @@ -142,7 +143,7 @@ public function testHandleChunk() { $this->request->method('file') ->willReturn(array( 'name'=> 'mock.png', - 'tmp_name'=> 'test/files/mock.png.003', + 'tmp_name'=> 'test/files/mock.png.0003', 'error'=> 0, 'size'=> 27000, )); @@ -154,7 +155,7 @@ public function testHandleChunk() { $this->resumbable->handleChunk(); $this->assertFileExists('test/uploads/mock.png'); - file_exists('test/tmp/identifier/mock.png.003') && unlink('test/tmp/identifier/mock.png.003'); + file_exists('test/tmp/identifier/mock.png.0003') && unlink('test/tmp/identifier/mock.png.0003'); unlink('test/uploads/mock.png'); } @@ -173,7 +174,7 @@ public function testResumableParamsGetRequest() ->getMock(); $this->request->method('is') - ->will($this->returnValue(true)); + ->willReturn(true); $this->request->method('data')->willReturn($resumableParams); @@ -181,7 +182,7 @@ public function testResumableParamsGetRequest() $this->assertEquals($resumableParams, $this->resumbable->resumableParams()); } - public function isFileUploadCompleteProvider() + public static function isFileUploadCompleteProvider() { return array( array('mock.png', 'files', 20, 60, true), From 72f438c03ac14013ceffbda003643e4f0a026dac Mon Sep 17 00:00:00 2001 From: Abilogos Date: Thu, 14 Dec 2023 15:53:45 +0300 Subject: [PATCH 14/14] make use of ResumableTotalChunks requestParam --- src/Resumable.php | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/Resumable.php b/src/Resumable.php index d76d5b4..a487237 100644 --- a/src/Resumable.php +++ b/src/Resumable.php @@ -47,7 +47,8 @@ class Resumable 'filename' => 'filename', 'chunkNumber' => 'chunkNumber', 'chunkSize' => 'chunkSize', - 'totalSize' => 'totalSize' + 'totalSize' => 'totalSize', + 'totalChunks' => 'totalChunks' ]; const WITHOUT_EXTENSION = true; @@ -178,12 +179,12 @@ public function handleTestChunk() $filename = $this->resumableParam($this->resumableOption['filename']); $chunkNumber = $this->resumableParam($this->resumableOption['chunkNumber']); $chunkSize = $this->resumableParam($this->resumableOption['chunkSize']); - $totalSize = $this->resumableParam($this->resumableOption['totalSize']); + $totalChunks = $this->resumableParam($this->resumableOption['totalChunks']); if (!$this->isChunkUploaded($identifier, $filename, $chunkNumber)) { return $this->response->header(204); } else { - if ($this->isFileUploadComplete($filename, $identifier, $chunkSize, $totalSize)) { + if ($this->isFileUploadComplete($filename, $identifier, $totalChunks)) { $this->isUploadComplete = true; $this->createFileAndDeleteTmp($identifier, $filename); return $this->response->header(201); @@ -200,14 +201,14 @@ public function handleChunk() $filename = $this->resumableParam($this->resumableOption['filename']); $chunkNumber = $this->resumableParam($this->resumableOption['chunkNumber']); $chunkSize = $this->resumableParam($this->resumableOption['chunkSize']); - $totalSize = $this->resumableParam($this->resumableOption['totalSize']); + $totalChunks = $this->resumableParam($this->resumableOption['totalChunks']); if (!$this->isChunkUploaded($identifier, $filename, $chunkNumber)) { $chunkFile = $this->tmpChunkDir($identifier) . DIRECTORY_SEPARATOR . $this->tmpChunkFilename($filename, $chunkNumber); $this->moveUploadedFile($file['tmp_name'], $chunkFile); } - if ($this->isFileUploadComplete($filename, $identifier, $chunkSize, $totalSize)) { + if ($this->isFileUploadComplete($filename, $identifier, $totalChunks)) { $this->isUploadComplete = true; $this->createFileAndDeleteTmp($identifier, $filename); return $this->response->header(201); @@ -265,13 +266,9 @@ public function resumableParams() } } - public function isFileUploadComplete($filename, $identifier, $chunkSize, $totalSize) + public function isFileUploadComplete($filename, $identifier, $totalChunks) { - if ($chunkSize <= 0) { - return false; - } - $numOfChunks = intval($totalSize / $chunkSize) + ($totalSize % $chunkSize == 0 ? 0 : 1); - for ($i = 1; $i <= $numOfChunks; $i++) { + for ($i = 1; $i <= $totalChunks; $i++) { if (!$this->isChunkUploaded($identifier, $filename, $i)) { return false; }