diff --git a/app/Http/Controllers/BundleController.php b/app/Http/Controllers/BundleController.php index ffaa085..78d2884 100644 --- a/app/Http/Controllers/BundleController.php +++ b/app/Http/Controllers/BundleController.php @@ -15,113 +15,119 @@ class BundleController extends Controller { // The bundle content preview - public function previewBundle(Request $request, Bundle $bundle) { + public function previewBundle(Request $request, Bundle $bundle) + { return view('download', [ 'bundle' => new BundleResource($bundle) ]); - } // The download method // - the bundle // - or just one file - public function downloadZip(Request $request, Bundle $bundle) { + public function downloadZip(Request $request, Bundle $bundle) + { - try { - // Download of the full bundle - // We must create a Zip archive - $bundle->downloads ++; - $bundle->save(); + // try { + // Download of the full bundle + // We must create a Zip archive + $bundle->downloads++; + $bundle->save(); - $filename = Storage::disk('uploads')->path('').'/'.$bundle->slug.'/bundle.zip'; - if (! file_exists($filename)) { - $bundlezip = fopen($filename, 'w'); + $filename = $bundle->slug . '/bundle.zip'; + if (!Storage::exists($filename)) { + // creating the zip archive + $zip = new ZipArchive; + $tempFilePath = tempnam(sys_get_temp_dir(), 'zip'); - // Creating the archive - $zip = new ZipArchive; - if (! @$zip->open($filename, ZipArchive::CREATE)) { - throw new Exception('Cannot initialize Zip archive'); - } - // Setting password when required - if (! empty($bundle->password)) { - $zip->setPassword($bundle->password); - } + if (!$zip->open($tempFilePath, ZipArchive::CREATE)) { + throw new Exception('Cannot initialize Zip archive'); + } - // Adding the files into the Zip with their real names - foreach ($bundle->files as $k => $file) { - if (file_exists(config('filesystems.disks.uploads.root').'/'.$file->fullpath)) { - $name = $file->original; + // Setting password when required + if (!empty($bundle->password)) { + $zip->setPassword($bundle->password); + } - // If a file in the archive has the same name - if (false !== $zip->locateName($name)) { - $i = 0; + // Adding the files into the Zip with their real names + foreach ($bundle->files as $k => $file) { + // get the bundle/filename + // dd((Storage::getConfig()['root'] ?? '') . '/' . $file->fullpath); + if (Storage::exists($file->fullpath)) { + $name = $file->original; + $stream = Storage::get($file->fullpath); - // Exploding the basename and extension - $basename = (false === strrpos($name, '.')) ? $name : substr($name, 0, strrpos($name, '.')); - $extension = (false === strrpos($name, '.')) ? null : substr($name, strrpos($name, '.')); + // If a file in the archive has the same name + if (false !== $zip->locateName($name)) { + $i = 0; - // Looping to find the right name - do { - $i++; - $newname = $basename.'-'.$i.$extension; - } - while ($zip->locateName($newname)); + // Exploding the basename and extension + $basename = (false === strrpos($name, '.')) ? $name : substr($name, 0, strrpos($name, '.')); + $extension = (false === strrpos($name, '.')) ? null : substr($name, strrpos($name, '.')); - // Final name was found - $name = $newname; - } - // Finally adding files - $zip->addFile(config('filesystems.disks.uploads.root').'/'.$file->fullpath, $name); + // Looping to find the right name + do { + $i++; + $newname = $basename . '-' . $i . $extension; + } while (false !== $zip->locateName($newname)); - if (! empty($bundle->password)) { - $zip->setEncryptionIndex($k, ZipArchive::EM_AES_256); - } + // Final name was found + $name = $newname; + dd(2); + } + // Finally adding files + $zip->addFromString($name, $stream); + + if (!empty($bundle->password)) { + $zip->setEncryptionIndex($k, ZipArchive::EM_AES_256); } } - - if (! @$zip->close()) { - throw new Exception('Cannot close Zip archive'); - } - - fclose($bundlezip); } + + if (!@$zip->close()) { + throw new Exception('Cannot close Zip archive'); + } + Storage::put($filename, file_get_contents($tempFilePath)); + } + + if (Storage::getConfig()['driver'] == 'local') { // Getting file size - $filesize = filesize($filename); + $filesize = filesize(Storage::path($filename)); // Let's download now - header('Content-Type: application/octet-stream'); - header('Content-Disposition: attachment; filename="'.Str::slug($bundle->title).'-'.time().'.zip'.'"'); - header('Cache-Control: no-cache, must-revalidate'); - header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); - header('Content-Length: '.$filesize); + return response()->streamDownload(function () use ($filename) { + // Downloading + if (config('sharing.download_limit_rate', false) !== false) { + $limit_rate = Upload::humanReadableToBytes(config('sharing.download_limit_rate')); - // Downloading - if (config('sharing.download_limit_rate', false) !== false) { - $limit_rate = Upload::humanReadableToBytes(config('sharing.download_limit_rate')); - - $fh = fopen($filename, 'rb'); - while (! feof($fh)) { - echo fread($fh, round($limit_rate)); - flush(); - sleep(1); + $fh = fopen(Storage::path($filename), 'rb'); + while (!feof($fh)) { + echo fread($fh, round($limit_rate)); + flush(); + sleep(1); + } + fclose($filename); + } else { + readfile(Storage::path($filename)); } - fclose($filename); - } - else { - readfile($filename); - } - exit; - + }, Str::slug($bundle->title) . '-' . time() . '.zip', [ + 'Content-Length' => $filesize, + 'Content-Type' => 'application/zip' + ]); + } else if (Storage::getConfig()['driver'] == 's3') { + // Cannot limit the download rate + return Storage::download($filename, Str::slug($bundle->title) . '-' . time() . '.zip'); + } else { + // Handle other drivers } - - // Could not find the metadata file - catch (Exception $e) { - abort(500, $e->getMessage()); - } - } + // Could not find the metadata file + // catch (Exception $e) { + // abort(500, $e->getMessage()); + // } + // } } diff --git a/app/Http/Controllers/UploadController.php b/app/Http/Controllers/UploadController.php index d8b229c..1936f12 100644 --- a/app/Http/Controllers/UploadController.php +++ b/app/Http/Controllers/UploadController.php @@ -16,7 +16,8 @@ use App\Models\File; class UploadController extends Controller { - public function createBundle(Request $request, Bundle $bundle) { + public function createBundle(Request $request, Bundle $bundle) + { return view('upload', [ 'bundle' => new BundleResource($bundle), 'baseUrl' => config('app.url') @@ -24,7 +25,8 @@ class UploadController extends Controller } // The upload form - public function storeBundle(Request $request, Bundle $bundle) { + public function storeBundle(Request $request, Bundle $bundle) + { try { $bundle->update([ @@ -36,8 +38,7 @@ class UploadController extends Controller ]); return response()->json(new BundleResource($bundle)); - } - catch (Exception $e) { + } catch (Exception $e) { return response()->json([ 'result' => false, 'message' => $e->getMessage() @@ -45,17 +46,18 @@ class UploadController extends Controller } } - public function uploadFile(Request $request, Bundle $bundle) { + public function uploadFile(Request $request, Bundle $bundle) + { // Validating form data $request->validate([ 'uuid' => 'required|uuid', - 'file' => 'required|file|max:'.(Upload::fileMaxSize() / 1000) + 'file' => 'required|file|max:' . (Upload::fileMaxSize() / 1000) ]); // Generating the file name $original = $request->file->getClientOriginalName(); - $filename = substr(sha1($original.time()), 0, rand(20, 30)); + $filename = substr(sha1($original . time()), 0, rand(20, 30)); // Moving file to final destination try { @@ -64,13 +66,14 @@ class UploadController extends Controller $hash = sha1_file($request->file->getPathname()); $existing = $bundle->files->whereNotNull('hash')->where('hash', $hash)->count(); - if (! empty($existing) && $existing > 0) { + if (!empty($existing) && $existing > 0) { throw new Exception(__('app.duplicate-file')); } } $fullpath = $request->file('file')->storeAs( - $bundle->slug, $filename, 'uploads' + $bundle->slug, + $filename ); // Generating file metadata $file = new File([ @@ -87,8 +90,7 @@ class UploadController extends Controller $file->save(); return response()->json(new FileResource($file)); - } - catch (Exception $e) { + } catch (Exception $e) { return response()->json([ 'result' => false, 'message' => $e->getMessage() @@ -96,7 +98,8 @@ class UploadController extends Controller } } - public function deleteFile(Request $request, Bundle $bundle) { + public function deleteFile(Request $request, Bundle $bundle) + { $request->validate([ 'uuid' => 'required|uuid' @@ -107,7 +110,7 @@ class UploadController extends Controller $file = File::findOrFail($request->uuid); // Physically deleting the file - if (! Storage::disk('uploads')->delete($file->fullpath)) { + if (!Storage::delete($file->fullpath)) { throw new Exception('Cannot delete file from disk'); } @@ -115,8 +118,7 @@ class UploadController extends Controller $file->delete(); return response()->json(new BundleResource($bundle)); - } - catch (Exception $e) { + } catch (Exception $e) { return response()->json([ 'result' => false, 'message' => $e->getMessage() @@ -125,7 +127,8 @@ class UploadController extends Controller } - public function completeBundle(Request $request, Bundle $bundle) { + public function completeBundle(Request $request, Bundle $bundle) + { // Processing size $size = 0; @@ -140,9 +143,8 @@ class UploadController extends Controller // Infinite expiry if ($bundle->expiry == 'forever') { $bundle->expires_at = null; - } - else { - $bundle->expires_at = time()+$bundle->expiry; + } else { + $bundle->expires_at = time() + $bundle->expiry; } $bundle->fullsize = $size; $bundle->preview_link = route('bundle.preview', ['bundle' => $bundle, 'auth' => $bundle->preview_token]); @@ -151,8 +153,7 @@ class UploadController extends Controller $bundle->save(); return response()->json(new BundleResource($bundle)); - } - catch (\Exception $e) { + } catch (\Exception $e) { return response()->json([ 'result' => false, 'message' => $e->getMessage() @@ -166,7 +167,8 @@ class UploadController extends Controller * We invalidate the expiry date and let the CRON * task do the hard work */ - public function deleteBundle(Request $request, Bundle $bundle) { + public function deleteBundle(Request $request, Bundle $bundle) + { try { // Forcing bundle to expire @@ -184,13 +186,11 @@ class UploadController extends Controller return response()->json([ 'success' => true ]); - } - catch (Exception $e) { + } catch (Exception $e) { return response()->json([ 'success' => false, 'message' => $e->getMessage() ], 500); } } - } diff --git a/composer.json b/composer.json index 9412774..8cff3a0 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,7 @@ "laravel/framework": "^10.8", "laravel/sanctum": "^3.2", "laravel/tinker": "^2.8", + "league/flysystem-aws-s3-v3": "^3.24", "ryangjchandler/orbit": "^1.2" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 68e5290..ba66b6f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,157 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "eb9f74c42bee8efdc1afdfe706ba40c3", + "content-hash": "f498eb116b2db824f3d207fb38abfb63", "packages": [ + { + "name": "aws/aws-crt-php", + "version": "v1.2.4", + "source": { + "type": "git", + "url": "https://github.com/awslabs/aws-crt-php.git", + "reference": "eb0c6e4e142224a10b08f49ebf87f32611d162b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/eb0c6e4e142224a10b08f49ebf87f32611d162b2", + "reference": "eb0c6e4e142224a10b08f49ebf87f32611d162b2", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35||^5.6.3||^9.5", + "yoast/phpunit-polyfills": "^1.0" + }, + "suggest": { + "ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality." + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "AWS SDK Common Runtime Team", + "email": "aws-sdk-common-runtime@amazon.com" + } + ], + "description": "AWS Common Runtime for PHP", + "homepage": "https://github.com/awslabs/aws-crt-php", + "keywords": [ + "amazon", + "aws", + "crt", + "sdk" + ], + "support": { + "issues": "https://github.com/awslabs/aws-crt-php/issues", + "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.4" + }, + "time": "2023-11-08T00:42:13+00:00" + }, + { + "name": "aws/aws-sdk-php", + "version": "3.300.12", + "source": { + "type": "git", + "url": "https://github.com/aws/aws-sdk-php.git", + "reference": "0c38aec51d8dc76d6b56a6be05c37b0aff86de2d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/0c38aec51d8dc76d6b56a6be05c37b0aff86de2d", + "reference": "0c38aec51d8dc76d6b56a6be05c37b0aff86de2d", + "shasum": "" + }, + "require": { + "aws/aws-crt-php": "^1.2.3", + "ext-json": "*", + "ext-pcre": "*", + "ext-simplexml": "*", + "guzzlehttp/guzzle": "^6.5.8 || ^7.4.5", + "guzzlehttp/promises": "^1.4.0 || ^2.0", + "guzzlehttp/psr7": "^1.9.1 || ^2.4.5", + "mtdowling/jmespath.php": "^2.6", + "php": ">=7.2.5", + "psr/http-message": "^1.0 || ^2.0" + }, + "require-dev": { + "andrewsville/php-token-reflection": "^1.4", + "aws/aws-php-sns-message-validator": "~1.0", + "behat/behat": "~3.0", + "composer/composer": "^1.10.22", + "dms/phpunit-arraysubset-asserts": "^0.4.0", + "doctrine/cache": "~1.4", + "ext-dom": "*", + "ext-openssl": "*", + "ext-pcntl": "*", + "ext-sockets": "*", + "nette/neon": "^2.3", + "paragonie/random_compat": ">= 2", + "phpunit/phpunit": "^5.6.3 || ^8.5 || ^9.5", + "psr/cache": "^1.0", + "psr/simple-cache": "^1.0", + "sebastian/comparator": "^1.2.3 || ^4.0", + "yoast/phpunit-polyfills": "^1.0" + }, + "suggest": { + "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", + "doctrine/cache": "To use the DoctrineCacheAdapter", + "ext-curl": "To send requests using cURL", + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-sockets": "To use client-side monitoring" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Aws\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Amazon Web Services", + "homepage": "http://aws.amazon.com" + } + ], + "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", + "homepage": "http://aws.amazon.com/sdkforphp", + "keywords": [ + "amazon", + "aws", + "cloud", + "dynamodb", + "ec2", + "glacier", + "s3", + "sdk" + ], + "support": { + "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", + "issues": "https://github.com/aws/aws-sdk-php/issues", + "source": "https://github.com/aws/aws-sdk-php/tree/3.300.12" + }, + "time": "2024-03-06T19:38:08+00:00" + }, { "name": "brick/math", "version": "0.11.0", @@ -1714,6 +1863,71 @@ ], "time": "2023-04-11T18:11:47+00:00" }, + { + "name": "league/flysystem-aws-s3-v3", + "version": "3.24.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-aws-s3-v3.git", + "reference": "809474e37b7fb1d1f8bcc0f8a98bc1cae99aa513" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-aws-s3-v3/zipball/809474e37b7fb1d1f8bcc0f8a98bc1cae99aa513", + "reference": "809474e37b7fb1d1f8bcc0f8a98bc1cae99aa513", + "shasum": "" + }, + "require": { + "aws/aws-sdk-php": "^3.295.10", + "league/flysystem": "^3.10.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "conflict": { + "guzzlehttp/guzzle": "<7.0", + "guzzlehttp/ringphp": "<1.1.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\AwsS3V3\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "AWS S3 filesystem adapter for Flysystem.", + "keywords": [ + "Flysystem", + "aws", + "file", + "files", + "filesystem", + "s3", + "storage" + ], + "support": { + "source": "https://github.com/thephpleague/flysystem-aws-s3-v3/tree/3.24.0" + }, + "funding": [ + { + "url": "https://ecologi.com/frankdejonge", + "type": "custom" + }, + { + "url": "https://github.com/frankdejonge", + "type": "github" + } + ], + "time": "2024-01-26T18:43:21+00:00" + }, { "name": "league/mime-type-detection", "version": "1.11.0", @@ -1871,6 +2085,72 @@ ], "time": "2023-02-06T13:46:10+00:00" }, + { + "name": "mtdowling/jmespath.php", + "version": "2.7.0", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "bbb69a935c2cbb0c03d7f481a238027430f6440b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/bbb69a935c2cbb0c03d7f481a238027430f6440b", + "reference": "bbb69a935c2cbb0c03d7f481a238027430f6440b", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^3.0.3", + "phpunit/phpunit": "^8.5.33" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "files": [ + "src/JmesPath.php" + ], + "psr-4": { + "JmesPath\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.7.0" + }, + "time": "2023-08-25T10:54:48+00:00" + }, { "name": "nesbot/carbon", "version": "2.66.0", diff --git a/package-lock.json b/package-lock.json index bcf4615..7badef7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "filesharing", + "name": "filesharing-contribute", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/yarn.lock b/yarn.lock index 9f044e2..41fbfd6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,10 +7,10 @@ resolved "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz" integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== -"@esbuild/darwin-arm64@0.17.18": +"@esbuild/win32-x64@0.17.18": version "0.17.18" - resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.18.tgz" - integrity sha512-6tY+djEAdF48M1ONWnQb1C+6LiXrKjmqjzPNPWXhu/GzOHTHX2nh8Mo2ZAmBFg0kIodHhciEgUBtcYCAIjGbjQ== + resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.18.tgz" + integrity sha512-qU25Ma1I3NqTSHJUOKi9sAH1/Mzuvlke0ioMJRthLXKm7JiSKVwFghlGbDLOO2sARECGhja4xYfRAZNPAkooYg== "@jridgewell/gen-mapping@^0.3.2": version "0.3.3" @@ -382,11 +382,6 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - function-bind@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"