├── .version
├── src
├── Contracts
│ └── .gitkeep
├── Exceptions
│ └── .gitkeep
├── Http
│ ├── Requests
│ │ └── .gitkeep
│ └── Controllers
│ │ ├── Controller.php
│ │ ├── BrowseController.php
│ │ ├── UploadController.php
│ │ ├── backup-code.txt
│ │ ├── DownloadController.php
│ │ ├── FileGroupController.php
│ │ ├── FileController.php
│ │ └── DirectoryController.php
├── FileManager.php
├── Traits
│ ├── RouteKeyNameUUID.php
│ ├── HasFile.php
│ ├── HasUUID.php
│ ├── ErrorHandler.php
│ ├── GetConstantsEnum.php
│ └── ApiResponder.php
├── Events
│ ├── File
│ │ ├── Moving.php
│ │ ├── Renaming.php
│ │ ├── AfterMove.php
│ │ ├── BeforeMove.php
│ │ ├── AfterRename.php
│ │ └── BeforeRename.php
│ ├── Image
│ │ ├── Resizing.php
│ │ ├── AfterResize.php
│ │ └── BeforeResize.php
│ ├── Upload
│ │ ├── AfterUpload.php
│ │ ├── Uploading.php
│ │ └── BeforeUpload.php
│ └── Event.php
├── Facades
│ └── FileManagerFacade.php
├── Enums
│ ├── FileStatusEnum.php
│ ├── DirectoryStatusEnum.php
│ └── FileTypeEnum.php
├── Jobs
│ ├── Job.php
│ ├── UploadFileProcess.php
│ └── UploadImageProcess.php
├── Services
│ ├── LoggerService.php
│ ├── FileGroupService.php
│ ├── Downloader.php
│ ├── MediaStream.php
│ ├── FileService.php
│ ├── ArchiveService.php
│ ├── DirectoryService.php
│ ├── Service.php
│ ├── UploadService.php
│ └── ImageService.php
├── Models
│ ├── FileGroup.php
│ ├── Directory.php
│ └── File.php
├── Console
│ └── Commands
│ │ ├── InitializePackageCommand.php
│ │ └── InstallPackageCommand.php
├── Providers
│ └── FileManagerServiceProvider.php
└── helpers.php
├── resources
├── assets
│ └── .gitkeep
└── lang
│ ├── ar
│ └── messages.php
│ ├── en
│ └── messages.php
│ ├── fa
│ └── messages.php
│ └── tr
│ └── messages.php
├── .github
└── FUNDING.yml
├── routes
├── filemanager-web.php
└── filemanger-api.php
├── CONTRIBUTING.md
├── CHANGELOG.md
├── .gitignore
├── test
└── FileTest.php
├── composer.json
├── todo.txt
├── frontend
└── test.blade.php
├── README-en.md
├── database
└── migrations
│ └── create_filemanager_tables.php.stub
├── config
└── filemanager.php
└── README.md
/.version:
--------------------------------------------------------------------------------
1 | v0.5.8
2 |
--------------------------------------------------------------------------------
/src/Contracts/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/Exceptions/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/resources/assets/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/Http/Requests/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | custom: ['https://idpay.ir/laravelir']
2 |
--------------------------------------------------------------------------------
/routes/filemanager-web.php:
--------------------------------------------------------------------------------
1 | morphMany(File::class);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Events/File/Moving.php:
--------------------------------------------------------------------------------
1 | uuid = (string)Uuid::generate(4);
15 | });
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/Traits/ErrorHandler.php:
--------------------------------------------------------------------------------
1 | errors, $error);
14 | }
15 |
16 | public function getErrors()
17 | {
18 | return $this->errors;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Http/Controllers/Controller.php:
--------------------------------------------------------------------------------
1 | '',
20 | 'files' => '',
21 | ];
22 |
23 | return $this->responseSuccess($data);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/Events/Event.php:
--------------------------------------------------------------------------------
1 | loggerService = resolve(LoggerService::class);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Enums/FileTypeEnum.php:
--------------------------------------------------------------------------------
1 | getConstants();
13 | }
14 |
15 | public static function getConstantValues()
16 | {
17 | $reflectionClass = new ReflectionClass(static::class); // __CLASS__
18 | return array_values($reflectionClass->getConstants());
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Jobs/Job.php:
--------------------------------------------------------------------------------
1 | file = $file;
20 | $this->uploadService = new UploadService();
21 | }
22 |
23 | public function handle()
24 | {
25 | $this->uploadService->uploadFile($this->file);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Jobs/UploadImageProcess.php:
--------------------------------------------------------------------------------
1 | file = $file;
20 | $this->uploadService = new UploadService();
21 | }
22 |
23 | public function handle()
24 | {
25 | $this->uploadService->uploadImage($this->file);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Services/LoggerService.php:
--------------------------------------------------------------------------------
1 | channel = config('filemanager.logger.channel');
14 | }
15 |
16 | public function log($msg, $level = 'debug')
17 | {
18 | if (!$this->checkLevel($level)) return false;
19 |
20 | Log::channel($this->channel)->$level($msg);
21 | }
22 |
23 | private function checkLevel($level)
24 | {
25 | $levels = ['emergency', 'alert', 'critical', 'error', 'warning', 'notice', 'info', 'debug'];
26 | return in_array($level, $levels);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Models/FileGroup.php:
--------------------------------------------------------------------------------
1 | belongsToMany(File::class, 'file_group_pivot');
24 | }
25 |
26 | public function __toString()
27 | {
28 | return "name: {$this->name}, size: {$this->size}, mime: {$this->mimeType}";
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/Traits/ApiResponder.php:
--------------------------------------------------------------------------------
1 | json([
11 | 'success' => true,
12 | 'status_code' => $statusCode,
13 | 'status_message' => $statusMessage,
14 | 'data' => $data
15 | ], $statusCode);
16 | }
17 |
18 | protected function responseError($data, $statusCode = 500, $statusMessage = "Error")
19 | {
20 | return response()->json([
21 | 'success' => false,
22 | 'status_code' => $statusCode,
23 | 'status_message' => $statusMessage,
24 | 'data' => $data
25 | ], $statusCode);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Http/Controllers/UploadController.php:
--------------------------------------------------------------------------------
1 | uploadService = $uploadService;
18 | }
19 |
20 | public function upload(Request $request)
21 | {
22 | $file = $request->file('file');
23 |
24 | // UploadFileProcess::dispatch($file);
25 |
26 | return $this->uploadService->uploadImage($file, 1);
27 | }
28 |
29 | public function uploadFiles(Request $request)
30 | {
31 | //
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Models/Directory.php:
--------------------------------------------------------------------------------
1 | belongsTo(Directory::class, 'parent_id', 'id');
23 | }
24 |
25 | // who created ?
26 | public function user()
27 | {
28 | return $this->belongsTo(config('filemanager.database.user_model'), 'user_id');
29 | }
30 |
31 | public function __toString()
32 | {
33 | return "name: {$this->name}, size: {$this->size}, mime: {$this->mimeType}";
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Http/Controllers/backup-code.txt:
--------------------------------------------------------------------------------
1 | public function getDirectoryBreadcrumb(Request $request)
2 | {
3 | // This probably could be better.
4 | $id = $request->input('folder');
5 |
6 | if ($id != 0) {
7 | // Get the current folder
8 | $folders = Directory::where('id', $id)->get();
9 |
10 | // See if it has a parent
11 | $parentId = $folders[0]["parent_folder"];
12 |
13 | if ($parentId != 0) {
14 | $looping = true;
15 |
16 | while ($looping) {
17 | // Get the parent details.
18 | $nextDirectory = Directory::where('id', $parentId)->get();
19 |
20 | $parentId = $nextDirectory[0]["parent_folder"];
21 |
22 | $folders = $folders->merge($nextDirectory);
23 |
24 | $looping = $parentId != 0;
25 | }
26 | }
27 |
28 | return $folders->toJson();
29 | }
30 |
31 | return null;
32 | }
33 |
--------------------------------------------------------------------------------
/test/FileTest.php:
--------------------------------------------------------------------------------
1 | assertEquals('10 B', File::getHumanReadableSize(10));
14 | $this->assertEquals('100 B', File::getHumanReadableSize(100));
15 | $this->assertEquals('1000 B', File::getHumanReadableSize(1000));
16 | $this->assertEquals('9.77 KB', File::getHumanReadableSize(10000));
17 | $this->assertEquals('976.56 KB', File::getHumanReadableSize(1000000));
18 | $this->assertEquals('9.54 MB', File::getHumanReadableSize(10000000));
19 | $this->assertEquals('9.31 GB', File::getHumanReadableSize(10000000000));
20 | }
21 |
22 | /** @test */
23 | public function it_can_determine_the_mime_type_of_a_file()
24 | {
25 | $this->assertEquals('text/x-php', File::getMimeType(__FILE__));
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Console/Commands/InitializePackageCommand.php:
--------------------------------------------------------------------------------
1 | disk = Storage::disk(config('filemanager.disk'));
24 | $this->base_directory = config('filemanager.base_directory');
25 |
26 | }
27 |
28 | public function handle()
29 | {
30 | $this->line("\n... Initialize package ...\n\n");
31 |
32 | if (!$this->disk->exists($this->base_directory)) {
33 | $this->disk->makeDirectory($this->base_directory, 755);
34 | }
35 |
36 | $this->line("Initialized ... \n");
37 |
38 | $this->warn("enjoy it, star me of github :) \n");
39 | $this->info("\t\tGood Luck.");
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/Http/Controllers/DownloadController.php:
--------------------------------------------------------------------------------
1 | fileModel = $file;
20 | }
21 |
22 | public function download(File $file)
23 | {
24 | $path = $file->path . DIRECTORY_SEPARATOR . $file->name;
25 |
26 | return Storage::disk($file->disk)->download($path, $file->name);
27 | }
28 |
29 | public function downloadFile($uuid)
30 | {
31 | $file = $this->fileModel->where('uuid', $uuid)->first();
32 |
33 | $secret = env('APP_KEY');
34 |
35 | $hash = $secret . $file->uuid . getUserIP() . request('t');
36 |
37 | if ((Carbon::createFromTimestamp(request('t')) > Carbon::now()) &&
38 | Hash::check($hash, request('mac'))
39 | ) {
40 | return response()->download();
41 | } else {
42 | throw new InternalErrorException("link not valid");
43 | }
44 |
45 | return response()->download(storage_path("app/uploads/") . $file->file_hash, $file->file_name);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Http/Controllers/FileGroupController.php:
--------------------------------------------------------------------------------
1 | fileGroupService = $fileGroupService;
18 | }
19 |
20 | public function index()
21 | {
22 | $fileGroups = $this->fileGroupService->allFileGroups();
23 | return $this->responseSuccess($fileGroups);
24 | }
25 |
26 | public function store(Request $request)
27 | {
28 | $fileGroups = $this->fileGroupService->createFileGroup($request->only(['title', 'description']));
29 | return $this->responseSuccess("FileGroup Created");
30 | }
31 |
32 | public function update(FileGroup $fileGroup, Request $request)
33 | {
34 | $fileGroups = $this->fileGroupService->updateFileGroup($fileGroup, $request->only(['title', 'description']));
35 | return $this->responseSuccess("FileGroup Updated");
36 | }
37 |
38 | public function delete(FileGroup $fileGroup)
39 | {
40 | $fileGroups = $this->fileGroupService->deleteFileGroup($fileGroup);
41 | return $this->responseSuccess("FileGroup Deleted");
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Services/FileGroupService.php:
--------------------------------------------------------------------------------
1 | model = new FileGroup();
19 | }
20 |
21 | public function allFileGroups()
22 | {
23 | return $this->model->all();
24 | }
25 |
26 | public function createFileGroup(array $data)
27 | {
28 | DB::transaction(function () use ($data) {
29 | $fileGroup = $this->model->create([
30 | 'title' => $data['title'],
31 | 'description' => $data['description'],
32 | ]);
33 | });
34 |
35 | return true;
36 | }
37 |
38 | public function updateFileGroup(FileGroup $fileGroup, $data)
39 | {
40 | DB::transaction(function () use ($fileGroup, $data) {
41 | $fileGroup->update([
42 | 'title' => $data['title'],
43 | 'description' => $data['description'],
44 | ]);
45 | });
46 |
47 | return true;
48 | }
49 |
50 | public function deleteFileGroup(FileGroup $fileGroup)
51 | {
52 | if ($fileGroup->delete())
53 | return true;
54 |
55 | return false;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "miladimos/laravel-filemanager",
3 | "description": "a powerful, flexible laravel file manager",
4 | "homepage": "https://github.com/miladimos/laravel-filemanager",
5 | "type": "library",
6 | "version": "0.6.4",
7 | "keywords": [
8 | "laravel",
9 | "laravel-filemanager",
10 | "laravel support",
11 | "lumen packages",
12 | "laravel packages",
13 | "lumen support",
14 | "file uploader",
15 | "uploader",
16 | "file manager"
17 | ],
18 | "authors": [
19 | {
20 | "name": "miladimos",
21 | "email": "miladimos@outlook.com",
22 | "role": "maintaner",
23 | "homepage": "https://github.com/miladimos"
24 | }
25 | ],
26 | "autoload": {
27 | "psr-4": {
28 | "Miladimos\\FileManager\\": "src/"
29 | },
30 | "files": [
31 | "src/helpers.php"
32 | ]
33 | },
34 | "extra": {
35 | "laravel": {
36 | "providers": [
37 | "Miladimos\\FileManager\\Providers\\FileManagerServiceProvider"
38 | ],
39 | "aliases": {
40 | "FileManager": "Miladimos\\FileManager\\Facades\\FileManagerFacade"
41 | }
42 | }
43 | },
44 | "require": {
45 | "php": ">=7.4|^8",
46 | "nesbot/carbon": "^2.50.0",
47 | "morilog/jalali": ">=v3.1.0",
48 | "intervention/image": "^2.6",
49 | "ramsey/uuid": "^4.1",
50 | "webpatser/laravel-uuid": "^4",
51 | "league/mime-type-detection": "^1.7"
52 | },
53 | "minimum-stability": "stable",
54 | "license": "MIT"
55 | }
56 |
--------------------------------------------------------------------------------
/src/Services/Downloader.php:
--------------------------------------------------------------------------------
1 | getTempFile($url);
36 | $this->guardAgainstInvalidMimeType($temporaryFile, $allowedMimeTypes);
37 |
38 | $filename = basename(parse_url($url, PHP_URL_PATH));
39 | $filename = urldecode($filename);
40 |
41 | if ($filename === '') {
42 | $filename = 'file';
43 | }
44 |
45 | if (!Str::contains($filename, '.')) {
46 | $mediaExtension = explode('/', mime_content_type($temporaryFile));
47 | $filename = "{$filename}.{$mediaExtension[1]}";
48 | }
49 |
50 | return app(FileAdderFactory::class)
51 | ->create($this, $temporaryFile)
52 | ->usingName(pathinfo($filename, PATHINFO_FILENAME))
53 | ->usingFileName($filename);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/todo.txt:
--------------------------------------------------------------------------------
1 | add logger / Log Service
2 |
3 | add error handler - error type and codes
4 |
5 | add ACL / advanced permissions ( maybe custom middleware or whatever )
6 |
7 | add transfer service between storages
8 |
9 | add jobs for upload, image resize, optimizer and ...
10 |
11 | add change visibility : public / private
12 |
13 | add notification system to specific users ( send email/sms to admin users) for specific operations
14 |
15 | add zip / tar comperes algorithms and download or store in current path file or dirs in zip / tar format
16 | Archives create/extract (zip, rar, 7z, tar, gzip, bzip2)
17 |
18 | add work with remote (ssh, ftp, sftp, dropbox) storages
19 |
20 | add pagination system
21 |
22 | add scheduled backup (store or send to ftp, email, ...)
23 |
24 | upload from url
25 |
26 | Chunked file upload for large file
27 |
28 | add statistics for all of activities
29 |
30 | Rich context menu and toolbar
31 |
32 | add auto watermark for images,videos
33 |
34 | add caching system
35 |
36 | ///// Frontend
37 |
38 | add code highlight
39 |
40 | Quick look, preview for common file types
41 |
42 | add advance filters, search
43 |
44 | add hide or visible items
45 |
46 | add breadcrumb manager
47 |
48 | multiple themes
49 |
50 | add frontend with livewire or ...
51 |
52 | https://www.bootdey.com/snippets/tagged/file-manager
53 |
54 | https://pixinvent.com/demo/vuexy-html-bootstrap-admin-template/html/rtl/vertical-menu-template/app-file-manager.html
55 |
56 | http://www.prepbootstrap.com/bootstrap-template/file-manager
57 |
58 | https://themeon.net/nifty/v2.9/app-file-manager.html
59 |
60 | https://demos.devexpress.com/MVCxFileManagerAndUploadDemos/FileManager/Templates
61 |
62 | https://dhtmlx.com/docs/products/demoApps/dhtmlxFileExplorerDemo/
63 |
64 | https://www.s-vfu.ru/stud/template/file-manager.html
65 |
66 | https://www.s-vfu.ru/stud/template/file-manager.html
67 |
68 | https://github.com/alexusmai/laravel-file-manager
69 |
70 |
71 |
--------------------------------------------------------------------------------
/frontend/test.blade.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
8 | Test File manager features
9 |
10 |
12 |
13 |
14 |
15 |
16 |
34 |
35 |
36 |
39 |
42 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/routes/filemanger-api.php:
--------------------------------------------------------------------------------
1 | 'directories.'], function () {
16 | // Route::get('directories', [DirectoryController::class, 'allDirectory'])->name('index');
17 | Route::post('/directories/{directory}/parent', [DirectoryController::class, 'getParentDirectory'])->name('parent');
18 |
19 | Route::post('directories', [DirectoryController::class, 'createDirectory'])->name('create');
20 | Route::delete('directories/{directory}', [DirectoryController::class, 'deleteDirectories'])->name('delete');
21 | Route::post('directories/{directory}/rename', [DirectoryController::class, 'renameDirectory'])->name('rename');
22 | });
23 |
24 | Route::group(['as' => 'files.'], function () {
25 | Route::delete('files/{file}', [FileController::class, 'deleteFile'])->name('delete');
26 | Route::post('files/{file}/rename', [FileController::class, 'renameFile'])->name('rename');
27 | Route::post('files/{file}/{directory}/move', [FileController::class, 'moveFile'])->name('move');
28 | });
29 |
30 | Route::group(['as' => 'uploads.'], function () {
31 | Route::post('upload', [UploadController::class, 'upload'])->name('upload');
32 | });
33 |
34 | Route::group(['as' => 'downloads.'], function () {
35 | //download/$file->uuid?mac=$hash&t=$timestamp
36 | Route::get("download/{file}?max={hash}&et={timestamp}", [DownloadController::class, 'download'])->name('download');
37 | });
38 |
39 | Route::group(['as' => 'filegroups.'], function () {
40 | Route::get('filegroups', [FileGroupController::class, 'index'])->name('index');
41 | Route::post('filegroups', [FileGroupController::class, 'store'])->name('store');
42 | Route::put('filegroups/{filegroup}/update', [FileGroupController::class, 'update'])->name('update');
43 | Route::delete('filegroups/{filegroup}', [FileGroupController::class, 'delete'])->name('delete');
44 | });
45 |
--------------------------------------------------------------------------------
/src/Http/Controllers/FileController.php:
--------------------------------------------------------------------------------
1 | fileService = $fileService;
18 | }
19 |
20 | public function renameFile(Request $request)
21 | {
22 | $file = $request->file;
23 | $new_name = $request->new_name;
24 |
25 | if ($this->fileService->rename($file, $new_name)) {
26 | return $this->responseSuccess("File Renamed");
27 | }
28 |
29 | return $this->responseError("Error in Rename File");
30 | }
31 |
32 | public function moveFile(Request $request)
33 | {
34 | $new_dir = $request->input('new_dir'); // id
35 | $file = $request->input('file');
36 |
37 | if ($this->fileService->moveFile($file, $new_dir)) {
38 | return $this->responseSuccess("File Moved");
39 | }
40 |
41 | return $this->responseError("Error in Move File");
42 | }
43 |
44 | public function deleteFile(File $file)
45 | {
46 | if ($this->fileService->deleteFile($file)) {
47 | return $this->responseSuccess("File Deleted");
48 | }
49 |
50 | return $this->responseError("Error in Delete File");
51 | }
52 |
53 | public function deleteFiles(Request $request)
54 | {
55 | if (is_array($request->input('files'))) {
56 | if ($this->fileService->deleteFiles($request->input('files'))) {
57 | return $this->responseError("All files Deleted.");
58 | }
59 | }
60 |
61 | return $this->responseError("files input is not array.");
62 | }
63 |
64 | public function getUserFiles(Request $request)
65 | {
66 | $user = $request->user_id;
67 | $directory = $request->has('directory') ? $request->directory : 0;
68 |
69 | if ($files = $this->fileService->getUserFiles($user, $directory)) {
70 | return $this->responseError($files);
71 | }
72 |
73 | return $this->responseError("Error in get user files.");
74 | }
75 |
76 | public function listAllFiles(Request $request)
77 | {
78 | //
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Console/Commands/InstallPackageCommand.php:
--------------------------------------------------------------------------------
1 | line("\t... Welcome To File Manager Package Installer ...");
19 |
20 | //config
21 | if (File::exists(config_path('filemanager.php'))) {
22 | $confirm = $this->confirm("filemanager.php already exist. Do you want to overwrite?");
23 | if ($confirm) {
24 | $this->publishConfig();
25 | } else {
26 | $this->error("you must overwrite config file");
27 | exit;
28 | }
29 | } else {
30 | $this->publishConfig();
31 | }
32 |
33 | // publish migration
34 | $this->publishMigration();
35 |
36 |
37 |
38 | $this->info("FileManager Package Successfully Installed. Star me on Github :) \n");
39 | $this->info("\t\tGood Luck.");
40 | }
41 |
42 | private function publishConfig()
43 | {
44 | $this->call('vendor:publish', [
45 | '--provider' => "Miladimos\FileManager\Providers\FileManagerServiceProvider",
46 | '--tag' => 'filemanager_config',
47 | '--force' => true
48 | ]);
49 | }
50 |
51 | private function publishMigration()
52 | {
53 | $this->call('vendor:publish', [
54 | '--provider' => "Miladimos\FileManager\Providers\FileManagerServiceProvider",
55 | '--tag' => 'filemanager-migrations',
56 | '--force' => true
57 | ]);
58 | }
59 |
60 | // //assets
61 | // if (File::exists(public_path('filemanager'))) {
62 | // $confirm = $this->confirm("filemanager directory already exist. Do you want to overwrite?");
63 | // if ($confirm) {
64 | // $this->publishAssets();
65 | // $this->info("assets overwrite finished");
66 | // } else {
67 | // $this->info("skipped assets publish");
68 | // }
69 | // } else {
70 | // $this->publishAssets();
71 | // $this->info("assets published");
72 | // }
73 |
74 | // private function publishAssets()
75 | // {
76 | // $this->call('vendor:publish', [
77 | // '--provider' => "Miladimos\FileManager\Providers\FileManagerServiceProvider",
78 | // '--tag' => 'assets',
79 | // '--force' => true
80 | // ]);
81 | // }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/resources/lang/ar/messages.php:
--------------------------------------------------------------------------------
1 | "Directory created",
5 | 'directory_active' => "Directory Is Active",
6 | 'directory_hide' => "Directory Is Hide",
7 | 'directory_locked' => "Directory is Locked",
8 | 'directory_private' => "Directory is Private",
9 | 'title' => 'File Manager',
10 | 'upload' => 'Upload',
11 | 'upload-message' => 'Drop files here to upload',
12 | 'success-upload' => 'Successfully uploaded!',
13 | 'search' => 'Search',
14 | 'doc' => 'Document',
15 | 'bulk-delete' => 'Bulk Del',
16 | 'preview' => 'Preview',
17 | 'name' => 'Name',
18 | 'size' => 'Size',
19 | 'type' => 'Type',
20 | 'mime' => 'Mime Type',
21 | 'extention' => 'Extention',
22 | 'modified' => 'Modified',
23 | 'created' => 'Created',
24 | 'dimension' => 'Dimension',
25 | 'action' => 'Action',
26 | 'bulk-select' => 'Bulk Select',
27 | 'showing-files' => 'Showing :current of :total files',
28 | 'edit' => 'Edit',
29 | 'update' => 'Update',
30 | 'convert' => 'Convert',
31 | 'format' => 'Format',
32 | 'choose_format' => 'Choose Format',
33 | "filemanager" => "SingleQuote FileManager",
34 | "files" => "Files",
35 | "folders" => "Folders",
36 | "my drive" => "My drive",
37 | "shared with me" => "Shared with me",
38 | "public" => "Public",
39 | "files uploading" => "Files uploading",
40 | "upload files" => "Upload files",
41 | "delete" => "Delete",
42 | "you are not allowed here" => "You are not allowed here",
43 | "this looks empty" => "This looks empty",
44 | "rename" => "Rename",
45 | "cancel" => "Cancel",
46 | "public drive" => "Public drive",
47 | "add folder" => "Add folder",
48 | "new folder" => "New folder",
49 | "folder name" => "Folder name",
50 | "details" => "Details",
51 | "filename" => "Filename",
52 | "created at" => "Created at",
53 | "last updated" => "Last updated",
54 | "mimetype" => "Mimetype",
55 | "extension" => "Extension",
56 | "uploader" => "Uploader",
57 | "unknown" => "Unknown",
58 | "enter email of the user(s)" => "Enter email of the user(s)",
59 | "share" => "Share",
60 | "share file" => "Share file",
61 | 'share folder' => "Share folder",
62 | "shared drive" => "Shared drive",
63 | "or anyone with this link" => "Or anyone with this link",
64 | "load more" => "Load more results",
65 | "storage" => "Storage",
66 | "shared with" => "Shared with",
67 | "remove the shared links" => "Remove the shared links",
68 | "can open" => "Can open",
69 | "can edit" => "Can edit",
70 | "can delete" => "Can delete",
71 | "can upload" => "Can upload",
72 | "permissions" => "Permissions",
73 | "open" => "Open"
74 | ];
75 |
--------------------------------------------------------------------------------
/resources/lang/en/messages.php:
--------------------------------------------------------------------------------
1 | "Directory created",
5 | 'directory_active' => "Directory Is Active",
6 | 'directory_hide' => "Directory Is Hide",
7 | 'directory_locked' => "Directory is Locked",
8 | 'directory_private' => "Directory is Private",
9 | 'title' => 'File Manager',
10 | 'upload' => 'Upload',
11 | 'upload-message' => 'Drop files here to upload',
12 | 'success-upload' => 'Successfully uploaded!',
13 | 'search' => 'Search',
14 | 'doc' => 'Document',
15 | 'bulk-delete' => 'Bulk Del',
16 | 'preview' => 'Preview',
17 | 'name' => 'Name',
18 | 'size' => 'Size',
19 | 'type' => 'Type',
20 | 'mime' => 'Mime Type',
21 | 'extention' => 'Extention',
22 | 'modified' => 'Modified',
23 | 'created' => 'Created',
24 | 'dimension' => 'Dimension',
25 | 'action' => 'Action',
26 | 'bulk-select' => 'Bulk Select',
27 | 'showing-files' => 'Showing :current of :total files',
28 | 'edit' => 'Edit',
29 | 'update' => 'Update',
30 | 'convert' => 'Convert',
31 | 'format' => 'Format',
32 | 'choose_format' => 'Choose Format',
33 | "filemanager" => "SingleQuote FileManager",
34 | "files" => "Files",
35 | "folders" => "Folders",
36 | "my drive" => "My drive",
37 | "shared with me" => "Shared with me",
38 | "public" => "Public",
39 | "files uploading" => "Files uploading",
40 | "upload files" => "Upload files",
41 | "delete" => "Delete",
42 | "you are not allowed here" => "You are not allowed here",
43 | "this looks empty" => "This looks empty",
44 | "rename" => "Rename",
45 | "cancel" => "Cancel",
46 | "public drive" => "Public drive",
47 | "add folder" => "Add folder",
48 | "new folder" => "New folder",
49 | "folder name" => "Folder name",
50 | "details" => "Details",
51 | "filename" => "Filename",
52 | "created at" => "Created at",
53 | "last updated" => "Last updated",
54 | "mimetype" => "Mimetype",
55 | "extension" => "Extension",
56 | "uploader" => "Uploader",
57 | "unknown" => "Unknown",
58 | "enter email of the user(s)" => "Enter email of the user(s)",
59 | "share" => "Share",
60 | "share file" => "Share file",
61 | 'share folder' => "Share folder",
62 | "shared drive" => "Shared drive",
63 | "or anyone with this link" => "Or anyone with this link",
64 | "load more" => "Load more results",
65 | "storage" => "Storage",
66 | "shared with" => "Shared with",
67 | "remove the shared links" => "Remove the shared links",
68 | "can open" => "Can open",
69 | "can edit" => "Can edit",
70 | "can delete" => "Can delete",
71 | "can upload" => "Can upload",
72 | "permissions" => "Permissions",
73 | "open" => "Open"
74 | ];
75 |
--------------------------------------------------------------------------------
/README-en.md:
--------------------------------------------------------------------------------
1 | - [](https://github.com/miladimos/laravel-filemanager/forks)
2 | - [](https://github.com/miladimos/laravel-filemanager/stargazers)
3 |
4 | - [فارسی](README.md)
5 |
6 |
7 | # laravel-file-uploads
8 | A package for convenient way to upload files to the different storages
9 |
10 | ### Installation
11 |
12 | 1. Run the command below to add this package:
13 | ```
14 | composer require miladimos/laravel-filemanager
15 | ```
16 |
17 | 2. Open your config/app.php and add the following to the providers array:
18 | ```php
19 | Miladimos\FileManager\Providers\FileManagerServiceProvider::class
20 | ```
21 |
22 | 3. Run the command below to install:
23 | ```
24 | php artisan filemanager:install
25 | ```
26 |
27 |
28 | ### Configuration
29 | Go to the file
30 |
31 | ```php
32 | config/file_uploads.php;
33 | ```
34 |
35 | There you have an ability to set:
36 |
37 | 1. default storage to upload file (default is: local)
38 | 2. default image quality (default is: 100)
39 | 3. default folder to put your uploads (default is: public/user-uploads)
40 |
41 | ### Usage
42 | To upload file:
43 |
44 | ```
45 | public function store(Request $request)
46 | {
47 | // This will upload your file to the default folder of selected in config storage
48 | Uploader::uploadFile($request->file('some_file'));
49 |
50 | // This will upload your file to the given as second parameter path of default storage
51 | Uploader::uploadFile($request->file('some_file'), 'path/to/upload');
52 |
53 | // This will upload your file to the given storage
54 | Uploader::uploadFile($request->file('some_file'), 'path/to/upload', 'storage_name');
55 |
56 | // This will also resize image to the given width and height
57 | Uploader::uploadFile($request->file('some_file'), 'path/to/upload', 'storage_name');
58 | }
59 | ```
60 |
61 |
62 | To upload base64 string of image:
63 |
64 | ```php
65 | public function store(Request $request)
66 | {
67 | // This will upload your file to the default folder of selected in config storage
68 | Uploader::uploadBase64Image($request->input('image'));
69 |
70 | // This will upload your file to the given as second parameter path of default storage
71 | Uploader::uploadFile($request->input('image'), 'path/to/upload');
72 |
73 | // This will upload your file to the given storage
74 | Uploader::uploadFile($request->input('image'), 'path/to/upload', 'storage_name');
75 |
76 | // This will also resize image to the given width and height
77 | Uploader::uploadFile($request->input('image'), 'path/to/upload', 'storage_name');
78 | }
79 | ```
80 |
--------------------------------------------------------------------------------
/src/Http/Controllers/DirectoryController.php:
--------------------------------------------------------------------------------
1 | directoryService = $directoryService;
19 | }
20 |
21 | public function createDirectory(Request $request)
22 | {
23 | $data = [
24 | 'name' => $request->get('name'),
25 | 'description' => $request->has('description') ? $request->input('description') : null,
26 | 'parent_id' => $request->has('parent_id') ? $request->input('parent_id') : 0,
27 | ];
28 |
29 | if ($this->directoryService->createDirectory($data)) {
30 | $msg = trans('filemanager::messages.directory_created');
31 | return $this->responseSuccess($msg, 201, "Created");
32 | }
33 |
34 | return $this->responseError("Error in Directory create", 500);
35 | }
36 |
37 | public function deleteDirectories(Request $request)
38 | {
39 | if (is_array($request->get('directories'))) {
40 | foreach ($request->get('directories', []) as $key => $directory) {
41 | if (!$this->directoryService->deleteDirectory($directory)) {
42 | return $this->responseError("Error in Directory Delete", 500);
43 | }
44 | }
45 | }
46 |
47 | if (!$this->directoryService->deleteDirectory($request->get('directories'))) {
48 | return $this->responseError("Error in Directory Delete", 500);
49 | }
50 |
51 | return $this->responseSuccess("Directories Deleted");
52 | }
53 |
54 | public function renameDirectory(Directory $directory, Request $request)
55 | {
56 | $name = $request->input('new_name');
57 |
58 | if (checkInstanceOf($directory, Directory::class)) {
59 | }
60 |
61 | return response()->json(['msg' => 'Directory renamed.', 'status' => '200'], 200);
62 | }
63 |
64 | public function getUserDirectorys(Request $request)
65 | {
66 | $folder = $request->input('folder');
67 |
68 | if ($folder == 0) {
69 | // get the parent folders
70 | $folders = Directory::where('parent_folder', '0')->where('user_id', Auth::id())->orderBy('folder_name', 'asc')->get();
71 | } else {
72 | $folders = Directory::where('parent_folder', $folder)->where('user_id', Auth::id())->orderBy('folder_name', 'asc')->get();
73 | }
74 |
75 | return $folders->toJson();
76 | }
77 |
78 | public function getParentDirectory(Directory $directory)
79 | {
80 | return $directory->parent();
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/database/migrations/create_filemanager_tables.php.stub:
--------------------------------------------------------------------------------
1 | id();
14 | $table->uuid('uuid')->uniuqe();
15 | $table->foreignID('parent_id')->nullable();
16 | $table->foreignID('user_id')->nullable();
17 | $table->string('disk');
18 | $table->string('name');
19 | $table->string('path');
20 | $table->string('color_hex')->nullable();
21 | $table->string('description')->nullable();
22 | $table->string('permission')->nullable();
23 | $table->char('status')->default('a');
24 | $table->timestamps();
25 | });
26 |
27 | Schema::create('filemanager_files', function (Blueprint $table) {
28 | $table->id();
29 | $table->uuid('uuid')->uniuqe();
30 | $table->string("fileable_type")->nullable();
31 | $table->unsignedBigInteger("fileable_id")->nullable();
32 | $table->foreignId('directory_id');
33 | $table->foreignId('user_id')->nullable()->comment('who made');
34 | $table->string('original_name');
35 | $table->string('disk');
36 | $table->string('name');
37 | $table->string('path');
38 | $table->string('url');
39 | $table->string('extension')->nullable();
40 | $table->string('mime_type')->nullable();
41 | $table->unsignedBigInteger('size')->nullable()->comment('in bytes');
42 | $table->char('type')->nullable();
43 | $table->char('status')->nullable();
44 | $table->string('width')->nullable();
45 | $table->string('height')->nullable();
46 | $table->string('description')->nullable();
47 | $table->string('permission')->nullable();
48 | $table->boolean('is_private')->default(false);
49 | $table->unsignedInteger('priority_column')->nullable();
50 | $table->timestamps();
51 | });
52 |
53 | Schema::create('filemanager_file_groups', function (Blueprint $table) {
54 | $table->id();
55 | $table->uuid('uuid')->uniuqe();
56 | $table->string('title')->unique();
57 | $table->string('description')->unique()->nullable();
58 | $table->boolean('active')->default(true);
59 | $table->timestamps();
60 | });
61 |
62 | Schema::create('filemanager_file_group_pivot', function (Blueprint $table) {
63 | $table->id();
64 | $table->morphs('groupable');
65 | $table->foreignId('group_id');
66 | });
67 | }
68 |
69 |
70 | public function down()
71 | {
72 | Schema::dropIfExists('filemanager_directories');
73 |
74 | Schema::dropIfExists('filemanager_files');
75 |
76 | Schema::dropIfExists('filemanager_file_groups');
77 |
78 | Schema::dropIfExists('filemanager_file_group_pivot');
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Providers/FileManagerServiceProvider.php:
--------------------------------------------------------------------------------
1 | mergeConfigFrom(__DIR__ . "/../../config/filemanager.php", 'filemanager');
17 |
18 | // $this->loadMigrationsFrom(__DIR__ . '/../../database/migrations');
19 |
20 | $this->registerViews();
21 |
22 | $this->registerFacades();
23 | }
24 |
25 | public function boot()
26 | {
27 | if ($this->app->runningInConsole()) {
28 | $this->registerConfig();
29 | $this->registerMigrations();
30 | $this->registerCommands();
31 | $this->registerTranslations();
32 | }
33 |
34 | $this->registerRoutes();
35 | }
36 |
37 | private function registerFacades()
38 | {
39 | $this->app->singleton('filemanager', FileManager::class);
40 | }
41 |
42 | private function registerConfig()
43 | {
44 | $this->publishes([
45 | __DIR__ . '/../../config/filemanager.php' => config_path('filemanager.php')
46 | ], 'filemanager_config');
47 | }
48 |
49 | private function registerTranslations()
50 | {
51 | $this->loadTranslationsFrom(__DIR__ . '/../resources/lang', 'filemanager');
52 |
53 | $this->publishes([
54 | __DIR__ . '/../resources/lang' => resource_path('lang/miladimos/laravel-filemanager'),
55 | ]);
56 | }
57 |
58 | private function registerViews()
59 | {
60 | $this->loadViewsFrom(__DIR__ . '/../../frontend', 'filemanager');
61 |
62 | $this->publishes([
63 | __DIR__ . '/../../frontend' => resource_path('views/miladimos/laravel-filemanager'),
64 | ]);
65 | }
66 |
67 | private function registerCommands()
68 | {
69 | $this->commands([
70 | InstallPackageCommand::class,
71 | InitializePackageCommand::class,
72 | ]);
73 | }
74 |
75 | private function registerMigrations()
76 | {
77 | // if (!class_exists('CreateFilemanagerTables')) {
78 | $this->publishes([
79 | __DIR__ . '/../../database/migrations/create_filemanager_tables.php.stub' => database_path('migrations/' . date('Y_m_d_His', time()) . '_create_filemanager_tables.php'),
80 | // you can add any number of migrations here
81 | ], 'filemanager-migrations');
82 | // }
83 | }
84 |
85 | private function registerRoutes()
86 | {
87 | Route::group($this->routeConfiguration(), function () {
88 | $this->loadRoutesFrom(__DIR__ . '/../../routes/filemanger-api.php', 'filemanager-routes');
89 | });
90 | }
91 |
92 | private function routeConfiguration()
93 | {
94 | $filemanager_api_version = 'V1';
95 |
96 | return [
97 | 'prefix' => config('filemanager.routes.api.api_prefix') . '/' . $filemanager_api_version . '/' . config('filemanager.routes.prefix'),
98 | 'middleware' => config('filemanager.routes.api.middleware'),
99 | 'as' => 'filemanager.'
100 | ];
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/helpers.php:
--------------------------------------------------------------------------------
1 | check()) {
28 | return false;
29 | }
30 |
31 | return auth($guard)->user();
32 | }
33 | }
34 |
35 | // if exists return true
36 | if (!function_exists('checkPath')) {
37 | function checkPath($path, $disk)
38 | {
39 | if ($disk && $path && \Illuminate\Support\Facades\Storage::disk($disk)->exists($path))
40 | return true;
41 | return false;
42 | }
43 | }
44 |
45 | if (!function_exists("getUserIP")) {
46 | function getUserIP()
47 | {
48 | $client = $_SERVER['HTTP_CLIENT_IP'];
49 | $forward = $_SERVER['HTTP_X_FORWARDED_FOR'];
50 | $remote = $_SERVER['REMOTE_ADDR'];
51 |
52 | if (filter_var($client, FILTER_VALIDATE_IP)) {
53 | $ip = $client;
54 | } elseif (filter_var($forward, FILTER_VALIDATE_IP)) {
55 | $ip = $forward;
56 | } else {
57 | $ip = $remote;
58 | }
59 |
60 | return $ip;
61 | }
62 | }
63 |
64 | if (!function_exists('decodeBase64File')) {
65 | function decodeBase64File($encodedFile)
66 | {
67 | // اینجا اطلاعات اضافی رو پاک میکنم تا کد اصلی رو بگیرم
68 | $file = str_replace(' ', '+', $encodedFile);
69 | $file = substr($file, strpos($file, ';base64,') + 8);
70 | $decodedFile = base64_decode($file);
71 |
72 | // با کمک توابع پی اچ پی، مشخصات فایل رو بررسی می کنم
73 | $fileMimeType = finfo_buffer(finfo_open(), $decodedFile, FILEINFO_MIME_TYPE);
74 | $fileExt = substr($fileMimeType, strpos($fileMimeType, '/') + 1);
75 |
76 | return [
77 | 'file' => $decodedFile, // فایل آماده برای ذخیره سازی در دیسک
78 | 'mime' => $fileMimeType, // نوع فایل
79 | 'ext' => $fileExt, // اکستنشن فایل
80 | 'size' => (int)strlen($decodedFile) // حجم فایل با واحد بایت
81 | ];
82 | }
83 | }
84 |
85 | if (!function_exists('version')) {
86 | function version(): string
87 | {
88 | return trim(file_get_contents(base_path('.version')));
89 | }
90 | }
91 |
92 | if (!function_exists('checkInstanceOf')) {
93 | function checkInstanceOf($varable, string $model): string
94 | {
95 | return !!($varable instanceof $model);
96 | }
97 | }
98 |
99 | if (!function_exists('generateDownloadHash')) {
100 | function generateDownloadHash(): string
101 | {
102 | return '';
103 | }
104 | }
105 |
106 | if (!function_exists('logActive')) {
107 | function logActive(): bool
108 | {
109 | return config('filemanager.logger.active');
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/Services/MediaStream.php:
--------------------------------------------------------------------------------
1 | zipName = $zipName;
28 |
29 | $this->mediaItems = collect();
30 |
31 | $this->zipOptions = new ArchiveOptions();
32 | }
33 |
34 | public function useZipOptions(callable $zipOptionsCallable): self
35 | {
36 | $zipOptionsCallable($this->zipOptions);
37 |
38 | return $this;
39 | }
40 |
41 | public function addMedia(...$mediaItems): self
42 | {
43 | collect($mediaItems)
44 | ->flatMap(function ($item) {
45 | if ($item instanceof Media) {
46 | return [$item];
47 | }
48 |
49 | if ($item instanceof Collection) {
50 | return $item->reduce(function (array $carry, Media $media) {
51 | $carry[] = $media;
52 |
53 | return $carry;
54 | }, []);
55 | }
56 |
57 | return $item;
58 | })
59 | ->each(fn (Media $media) => $this->mediaItems->push($media));
60 |
61 | return $this;
62 | }
63 |
64 | public function getMediaItems(): Collection
65 | {
66 | return $this->mediaItems;
67 | }
68 |
69 | public function toResponse($request): StreamedResponse
70 | {
71 | $headers = [
72 | 'Content-Disposition' => "attachment; filename=\"{$this->zipName}\"",
73 | 'Content-Type' => 'application/octet-stream',
74 | ];
75 |
76 | return new StreamedResponse(fn () => $this->getZipStream(), 200, $headers);
77 | }
78 |
79 | public function getZipStream(): ZipStream
80 | {
81 | $zip = new ZipStream($this->zipName, $this->zipOptions);
82 |
83 | $this->getZipStreamContents()->each(function (array $mediaInZip) use ($zip) {
84 | $stream = $mediaInZip['media']->stream();
85 |
86 | $zip->addFileFromStream($mediaInZip['fileNameInZip'], $stream);
87 |
88 | if (is_resource($stream)) {
89 | fclose($stream);
90 | }
91 | });
92 |
93 | $zip->finish();
94 |
95 | return $zip;
96 | }
97 |
98 | protected function getZipStreamContents(): Collection
99 | {
100 | return $this->mediaItems->map(fn (Media $media, $mediaItemIndex) => [
101 | 'fileNameInZip' => $this->getZipFileNamePrefix($this->mediaItems, $mediaItemIndex).$this->getFileNameWithSuffix($this->mediaItems, $mediaItemIndex),
102 | 'media' => $media,
103 | ]);
104 | }
105 |
106 | protected function getFileNameWithSuffix(Collection $mediaItems, int $currentIndex): string
107 | {
108 | $fileNameCount = 0;
109 |
110 | $fileName = $mediaItems[$currentIndex]->file_name;
111 |
112 | foreach ($mediaItems as $index => $media) {
113 | if ($index >= $currentIndex) {
114 | break;
115 | }
116 |
117 | if ($this->getZipFileNamePrefix($mediaItems, $index).$media->file_name === $this->getZipFileNamePrefix($mediaItems, $currentIndex).$fileName) {
118 | $fileNameCount++;
119 | }
120 | }
121 |
122 | if ($fileNameCount === 0) {
123 | return $fileName;
124 | }
125 |
126 | $extension = pathinfo($fileName, PATHINFO_EXTENSION);
127 | $fileNameWithoutExtension = pathinfo($fileName, PATHINFO_FILENAME);
128 |
129 | return "{$fileNameWithoutExtension} ({$fileNameCount}).{$extension}";
130 | }
131 |
132 | protected function getZipFileNamePrefix(Collection $mediaItems, int $currentIndex): string
133 | {
134 | return $mediaItems[$currentIndex]->hasCustomProperty('zip_filename_prefix') ? $mediaItems[$currentIndex]->getCustomProperty('zip_filename_prefix') : '';
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/src/Services/FileService.php:
--------------------------------------------------------------------------------
1 | model = new File();
24 | }
25 |
26 | public function rename(File $file, $newFileName)
27 | {
28 |
29 | if (!checkPath($file->path, $this->disk_name)) {
30 | return false;
31 | }
32 |
33 | if ($this->disk->move(($file->path . $this->ds . $file->name), $file->path . $this->ds . $newFileName)) {
34 |
35 | DB::transaction(function () use ($file, $newFileName) {
36 | $this->model->where('name', $file->name)->update([
37 | 'name' => $newFileName,
38 | ]);
39 | });
40 |
41 | return true;
42 | }
43 |
44 | return false;
45 | }
46 |
47 | public function moveFile(File $file, Directory $newdir)
48 | {
49 |
50 | if (!checkPath($file->path, $this->disk_name)) {
51 | return false;
52 | }
53 |
54 | if ($this->disk->move($file->path, $newdir->path)) {
55 | DB::transaction(function () use ($file, $newdir) {
56 | $this->model->where('id', $file)->update([
57 | 'directory_id' => $newdir->id,
58 | 'path' => $newdir->path
59 | ]);
60 | });
61 | }
62 |
63 | return false;
64 | }
65 |
66 | public function copyFile(File $file, Directory $new_dir)
67 | {
68 |
69 | if (!checkPath($file->path, $this->disk_name)) {
70 | return false;
71 | }
72 |
73 | if ($this->disk->copy($file->path, $new_dir->path)) {
74 | DB::transaction(function () use ($file, $new_dir) {
75 | $this->model->where('id', $file)->update([
76 | 'directory_id' => $new_dir,
77 | 'path' => $new_dir->path
78 | ]);
79 | });
80 |
81 | return true;
82 | }
83 |
84 | return false;
85 | }
86 |
87 | public function deleteFile(File $file)
88 | {
89 | if (!checkPath($file->path, $this->disk_name)) {
90 | return false;
91 | }
92 |
93 | if ($this->disk->delete($file->path)) {
94 | $file->forceDelete();
95 |
96 | return true;
97 | }
98 |
99 | return false;
100 | }
101 |
102 | public function getUserFiles($user, $directory)
103 | {
104 | // all files in everywhere
105 | if ($directory == 0) {
106 | $files = $this->model->where('user_id', $user)->latest()->get();
107 | } else {
108 | $files = $this->model->where('directory_id', $directory)->where('user_id', $user)->latest()->get();
109 | }
110 |
111 | return $files;
112 | }
113 |
114 | /**
115 | * generate the link for download file
116 | * this link has expire time
117 | *
118 | * @return string
119 | */
120 | public function generateLink($uuid)
121 | {
122 | $file = File::where('uuid', $uuid)->first();
123 |
124 | $secret = env('APP_KEY');
125 |
126 | $expireTime = (int)config('filemanager.download_link_expire');
127 |
128 | $timestamp = Carbon::now()->addMinutes($expireTime)->timestamp;
129 | $hash = Hash::make($secret . $file->uuid . getUserIP() . $timestamp);
130 |
131 | // return "/api/filemanager/download/$file->uuid?mac=$hash&t=$timestamp";
132 | return route('filemanager.download', [$file, $hash, $timestamp]);
133 | }
134 |
135 | /**
136 | * Return the full web path to a file.
137 | *
138 | * @param $path
139 | *
140 | * @return string
141 | */
142 | public function fileWebpath($path)
143 | {
144 | $path = $this->disk->url($path);
145 | // Remove extra slashes from URL without removing first two slashes after http/https:...
146 | $path = preg_replace('/([^:])(\/{2,})/', '$1/', $path);
147 |
148 | return $path;
149 | }
150 |
151 | /**
152 | * @param $path
153 | *
154 | * @return string
155 | */
156 | private function fileRelativePath($path)
157 | {
158 | $path = $this->fileWebpath($path);
159 | // @todo This wont work for files not located on the current server...
160 | $path = Str::replaceFirst(env('APP_URL'), '', $path);
161 | $path = str_replace(' ', '%20', $path);
162 |
163 | return $path;
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/resources/lang/fa/messages.php:
--------------------------------------------------------------------------------
1 | "Directory Is Active",
5 | 'directory_hide' => "Directory Is Hide",
6 | 'directory_locked' => "Directory is Locked",
7 | 'directory_private' => "Directory is Private",
8 | 'directory_created' => "دایرکتوری ایجاد شد",
9 | 'title' => 'مدیریت فایل',
10 | 'upload' => 'آپلود',
11 | 'upload-message' => 'Drop files here to upload',
12 | 'success-upload' => 'با موفقیت آپلود شد',
13 | 'search' => 'جستجو',
14 | 'doc' => 'Document',
15 | 'preview' => 'پیش نمایش',
16 | 'name' => 'نام',
17 | 'size' => 'سایز',
18 | 'type' => 'نوع',
19 | 'mime' => 'Mime Type',
20 | 'extention' => 'پسوند',
21 | 'modified' => 'تغییر کرده',
22 | 'created' => 'ایجاد شده',
23 | 'dimension' => 'Dimension',
24 | 'action' => 'عملیات',
25 | 'showing-files' => 'Showing :current of :total files',
26 | 'edit' => 'ویرایش',
27 | 'update' => 'آپدیت',
28 | 'convert' => 'تبدیل',
29 | 'format' => 'فرمت',
30 | 'choose_format' => 'انتخاب فرمت',
31 | "files" => "فایل ها",
32 | "folders" => "فولدر ها",
33 | "my drive" => "My drive",
34 | "shared with me" => "با من به اشتراک بزار",
35 | "public" => "عمومی",
36 | "files uploading" => "فایل ها در حال آپلود ...",
37 | "upload files" => "آبلود فایل ها",
38 | "delete" => "حذف",
39 | "you are not allowed here" => "You are not allowed here",
40 | "rename" => "تغیر نام",
41 | "cancel" => "انصراف",
42 | "public drive" => "Public drive",
43 | "add folder" => "افزودن دایرکتوری",
44 | "new folder" => "New folder",
45 | "details" => "توضیحات",
46 | "filename" => "نام فایل",
47 | "created at" => "ایجاد شده در",
48 | "last updated" => "آخرین بروزرسانی",
49 | "mimetype" => "Mimetype",
50 | "extension" => "Extension",
51 | "uploader" => "Uploader",
52 | "unknown" => "Unknown",
53 | "enter email of the user(s)" => "Enter email of the user(s)",
54 | "share" => "اشتراک گذاری",
55 | "share file" => "Share file",
56 | 'share folder' => "Share folder",
57 | "shared drive" => "Shared drive",
58 | "or anyone with this link" => "Or anyone with this link",
59 | "load more" => "Load more results",
60 | "storage" => "Storage",
61 | "shared with" => "Shared with",
62 | "remove the shared links" => "Remove the shared links",
63 | "can open" => "Can open",
64 | "can edit" => "Can edit",
65 | "can delete" => "Can delete",
66 | "can upload" => "Can upload",
67 | "permissions" => "سطح دسترسی ها",
68 | "open" => "باز کردن",
69 | 'nav-back' => 'بازگشت',
70 | 'nav-new' => 'پوشه جدید',
71 | 'nav-upload' => 'آپلود',
72 | 'nav-thumbnails' => 'تصویرک ها',
73 | 'nav-list' => 'لیست',
74 | 'nav-sort' => 'مرتب سازی',
75 | 'nav-sort-alphabetic' => 'مرتب سازی الفبایی',
76 | 'nav-sort-time' => 'مرتب سازی زمانی',
77 | 'menu-rename' => 'تغییر نام',
78 | 'menu-delete' => 'حذف',
79 | 'menu-view' => 'مشاهده',
80 | 'menu-download' => 'دانلود',
81 | 'menu-resize' => 'تغییر اندازه',
82 | 'menu-crop' => 'برش',
83 | 'menu-move' => 'انتقال',
84 | 'menu-multiple' => 'انتخاب چندتایی',
85 |
86 | 'title-page' => 'مدیریت فایل',
87 | 'title-panel' => 'مدیریت فایل لاراول',
88 | 'title-upload' => 'آپلود فایل',
89 | 'title-view' => 'مشاهده فایل',
90 | 'title-user' => 'فایل ها',
91 | 'title-share' => 'فایل های اشتراکی',
92 | 'title-item' => 'آیتم',
93 | 'title-size' => 'اندازه',
94 | 'title-type' => 'نوع',
95 | 'title-modified' => 'تاریخ آخرین ویرایش',
96 | 'title-action' => 'اقدام',
97 |
98 | 'type-folder' => 'پوشه',
99 |
100 | 'message-empty' => 'پوشه خالی است.',
101 | 'message-choose' => 'انتخاب فایل',
102 | 'message-delete' => 'آیا از حذف این آیتم مطمئن هستید؟',
103 | 'message-name' => 'نام پوشه:',
104 | 'message-rename' => 'تغییر نام به:',
105 | 'message-extension_not_found' => 'لطفا gd یا imagick را برای برش، تغییر اندازه و ایجاد تصویرک نصب کنید.',
106 | 'message-drop' => 'یا فایل ها را برای آپلود اینجا رها کنید',
107 |
108 | 'error-rename' => 'این نام قبلا استفاده شده!',
109 | 'error-file-name' => 'نام فایل نباید خالی باشد!',
110 | 'error-file-empty' => 'باید یک فایل انتخاب کنید!',
111 | 'error-file-exist' => 'فایلی با این نام از قبل وجود دارد!',
112 | 'error-file-size' => 'محدودیت حجم فایل سرور! (حداکثر حجم: :max)',
113 | 'error-delete-folder' => 'به دلیل خالی نبودن پوشه امکان حذف آن وجود ندارد!',
114 | 'error-folder-name' => 'نام پوشه نمی تواند خالی باشد!',
115 | 'error-folder-exist' => 'پوشه ای با این نام از قبل وجود دارد!',
116 | 'error-folder-alnum' => 'فقط اسامی الفبایی برای پوشه مجاز است!',
117 | 'error-folder-not-found' => 'پوشهای یافت نشد! (:folder)',
118 | 'error-mime' => 'پسوند غیرمجاز: ',
119 | 'error-size' => 'سایز بیش از حد:',
120 | 'error-instance' => 'فایل آپلود شده باید نمونه ای از UploadedFile باشد',
121 | 'error-invalid' => 'درخواست آپلود غیرمعتبر',
122 | 'error-other' => 'خطایی رخ داد: ',
123 | 'error-too-large' => 'درخواست موجودیت خیلی طولانیست!',
124 |
125 | 'btn-upload' => 'آپلود فایل',
126 | 'btn-uploading' => 'در حال آپلود',
127 | 'btn-close' => 'بستن',
128 | 'btn-crop' => 'برش',
129 | 'btn-copy-crop' => 'برش و ذخیره در فایل جدید',
130 | 'btn-crop-free' => 'برش آزاد',
131 | 'btn-cancel' => 'انصراف',
132 | 'btn-confirm' => 'تایید',
133 | 'btn-resize' => 'تغییر اندازه',
134 | 'btn-open' => 'باز کردن پوشه',
135 |
136 | 'resize-ratio' => 'نسبت:',
137 | 'resize-scaled' => 'تصویر مقیاس شده:',
138 | 'resize-true' => 'بله',
139 | 'resize-old-height' => 'ارتفاع اصلی:',
140 | 'resize-old-width' => 'عرض اصلی:',
141 | 'resize-new-height' => 'ارتفاع:',
142 | 'resize-new-width' => 'عرض:',
143 |
144 | 'locale-bootbox' => 'fa',
145 | ];
146 |
--------------------------------------------------------------------------------
/resources/lang/tr/messages.php:
--------------------------------------------------------------------------------
1 | "Directory Is Active",
5 | 'directory_hide' => "Directory Is Hide",
6 | 'directory_locked' => "Directory is Locked",
7 | 'directory_private' => "Directory is Private",
8 | 'directory_created' => "دایرکتوری ایجاد شد",
9 | 'title' => 'مدیریت فایل',
10 | 'upload' => 'آپلود',
11 | 'upload-message' => 'Drop files here to upload',
12 | 'success-upload' => 'با موفقیت آپلود شد',
13 | 'search' => 'جستجو',
14 | 'doc' => 'Document',
15 | 'preview' => 'پیش نمایش',
16 | 'name' => 'نام',
17 | 'size' => 'سایز',
18 | 'type' => 'نوع',
19 | 'mime' => 'Mime Type',
20 | 'extention' => 'پسوند',
21 | 'modified' => 'تغییر کرده',
22 | 'created' => 'ایجاد شده',
23 | 'dimension' => 'Dimension',
24 | 'action' => 'عملیات',
25 | 'showing-files' => 'Showing :current of :total files',
26 | 'edit' => 'ویرایش',
27 | 'update' => 'آپدیت',
28 | 'convert' => 'تبدیل',
29 | 'format' => 'فرمت',
30 | 'choose_format' => 'انتخاب فرمت',
31 | "files" => "فایل ها",
32 | "folders" => "فولدر ها",
33 | "my drive" => "My drive",
34 | "shared with me" => "با من به اشتراک بزار",
35 | "public" => "عمومی",
36 | "files uploading" => "فایل ها در حال آپلود ...",
37 | "upload files" => "آبلود فایل ها",
38 | "delete" => "حذف",
39 | "you are not allowed here" => "You are not allowed here",
40 | "rename" => "تغیر نام",
41 | "cancel" => "انصراف",
42 | "public drive" => "Public drive",
43 | "add folder" => "افزودن دایرکتوری",
44 | "new folder" => "New folder",
45 | "details" => "توضیحات",
46 | "filename" => "نام فایل",
47 | "created at" => "ایجاد شده در",
48 | "last updated" => "آخرین بروزرسانی",
49 | "mimetype" => "Mimetype",
50 | "extension" => "Extension",
51 | "uploader" => "Uploader",
52 | "unknown" => "Unknown",
53 | "enter email of the user(s)" => "Enter email of the user(s)",
54 | "share" => "اشتراک گذاری",
55 | "share file" => "Share file",
56 | 'share folder' => "Share folder",
57 | "shared drive" => "Shared drive",
58 | "or anyone with this link" => "Or anyone with this link",
59 | "load more" => "Load more results",
60 | "storage" => "Storage",
61 | "shared with" => "Shared with",
62 | "remove the shared links" => "Remove the shared links",
63 | "can open" => "Can open",
64 | "can edit" => "Can edit",
65 | "can delete" => "Can delete",
66 | "can upload" => "Can upload",
67 | "permissions" => "سطح دسترسی ها",
68 | "open" => "باز کردن",
69 | 'nav-back' => 'بازگشت',
70 | 'nav-new' => 'پوشه جدید',
71 | 'nav-upload' => 'آپلود',
72 | 'nav-thumbnails' => 'تصویرک ها',
73 | 'nav-list' => 'لیست',
74 | 'nav-sort' => 'مرتب سازی',
75 | 'nav-sort-alphabetic' => 'مرتب سازی الفبایی',
76 | 'nav-sort-time' => 'مرتب سازی زمانی',
77 | 'menu-rename' => 'تغییر نام',
78 | 'menu-delete' => 'حذف',
79 | 'menu-view' => 'مشاهده',
80 | 'menu-download' => 'دانلود',
81 | 'menu-resize' => 'تغییر اندازه',
82 | 'menu-crop' => 'برش',
83 | 'menu-move' => 'انتقال',
84 | 'menu-multiple' => 'انتخاب چندتایی',
85 |
86 | 'title-page' => 'مدیریت فایل',
87 | 'title-panel' => 'مدیریت فایل لاراول',
88 | 'title-upload' => 'آپلود فایل',
89 | 'title-view' => 'مشاهده فایل',
90 | 'title-user' => 'فایل ها',
91 | 'title-share' => 'فایل های اشتراکی',
92 | 'title-item' => 'آیتم',
93 | 'title-size' => 'اندازه',
94 | 'title-type' => 'نوع',
95 | 'title-modified' => 'تاریخ آخرین ویرایش',
96 | 'title-action' => 'اقدام',
97 |
98 | 'type-folder' => 'پوشه',
99 |
100 | 'message-empty' => 'پوشه خالی است.',
101 | 'message-choose' => 'انتخاب فایل',
102 | 'message-delete' => 'آیا از حذف این آیتم مطمئن هستید؟',
103 | 'message-name' => 'نام پوشه:',
104 | 'message-rename' => 'تغییر نام به:',
105 | 'message-extension_not_found' => 'لطفا gd یا imagick را برای برش، تغییر اندازه و ایجاد تصویرک نصب کنید.',
106 | 'message-drop' => 'یا فایل ها را برای آپلود اینجا رها کنید',
107 |
108 | 'error-rename' => 'این نام قبلا استفاده شده!',
109 | 'error-file-name' => 'نام فایل نباید خالی باشد!',
110 | 'error-file-empty' => 'باید یک فایل انتخاب کنید!',
111 | 'error-file-exist' => 'فایلی با این نام از قبل وجود دارد!',
112 | 'error-file-size' => 'محدودیت حجم فایل سرور! (حداکثر حجم: :max)',
113 | 'error-delete-folder' => 'به دلیل خالی نبودن پوشه امکان حذف آن وجود ندارد!',
114 | 'error-folder-name' => 'نام پوشه نمی تواند خالی باشد!',
115 | 'error-folder-exist' => 'پوشه ای با این نام از قبل وجود دارد!',
116 | 'error-folder-alnum' => 'فقط اسامی الفبایی برای پوشه مجاز است!',
117 | 'error-folder-not-found' => 'پوشهای یافت نشد! (:folder)',
118 | 'error-mime' => 'پسوند غیرمجاز: ',
119 | 'error-size' => 'سایز بیش از حد:',
120 | 'error-instance' => 'فایل آپلود شده باید نمونه ای از UploadedFile باشد',
121 | 'error-invalid' => 'درخواست آپلود غیرمعتبر',
122 | 'error-other' => 'خطایی رخ داد: ',
123 | 'error-too-large' => 'درخواست موجودیت خیلی طولانیست!',
124 |
125 | 'btn-upload' => 'آپلود فایل',
126 | 'btn-uploading' => 'در حال آپلود',
127 | 'btn-close' => 'بستن',
128 | 'btn-crop' => 'برش',
129 | 'btn-copy-crop' => 'برش و ذخیره در فایل جدید',
130 | 'btn-crop-free' => 'برش آزاد',
131 | 'btn-cancel' => 'انصراف',
132 | 'btn-confirm' => 'تایید',
133 | 'btn-resize' => 'تغییر اندازه',
134 | 'btn-open' => 'باز کردن پوشه',
135 |
136 | 'resize-ratio' => 'نسبت:',
137 | 'resize-scaled' => 'تصویر مقیاس شده:',
138 | 'resize-true' => 'بله',
139 | 'resize-old-height' => 'ارتفاع اصلی:',
140 | 'resize-old-width' => 'عرض اصلی:',
141 | 'resize-new-height' => 'ارتفاع:',
142 | 'resize-new-width' => 'عرض:',
143 |
144 | 'locale-bootbox' => 'fa',
145 | ];
146 |
--------------------------------------------------------------------------------
/src/Services/ArchiveService.php:
--------------------------------------------------------------------------------
1 | zip = $zip;
30 | $this->request = $request;
31 | $this->pathPrefix = Storage::disk($request->input('disk'))
32 | ->getDriver()
33 | ->getAdapter()
34 | ->getPathPrefix();
35 | }
36 |
37 | /**
38 | * Create new zip archive
39 | *
40 | * @return array
41 | */
42 | public function create()
43 | {
44 |
45 | if ($this->createArchive()) {
46 | return [
47 | 'result' => [
48 | 'status' => 'success',
49 | 'message' => null,
50 | ],
51 | ];
52 | }
53 |
54 | return [
55 | 'result' => [
56 | 'status' => 'warning',
57 | 'message' => 'zipError',
58 | ],
59 | ];
60 | }
61 |
62 | /**
63 | * Extract
64 | *
65 | * @return array
66 | */
67 | public function extract()
68 | {
69 | if ($this->extractArchive()) {
70 | return [
71 | 'result' => [
72 | 'status' => 'success',
73 | 'message' => null,
74 | ],
75 | ];
76 | }
77 |
78 | return [
79 | 'result' => [
80 | 'status' => 'warning',
81 | 'message' => 'zipError',
82 | ],
83 | ];
84 | }
85 |
86 | /**
87 | * Create zip archive
88 | *
89 | * @return bool
90 | */
91 | protected function createArchive()
92 | {
93 | // elements list
94 | $elements = $this->request->input('elements');
95 |
96 | // create or overwrite archive
97 | if (
98 | $this->zip->open(
99 | $this->createName(),
100 | ZIPARCHIVE::OVERWRITE | ZIPARCHIVE::CREATE
101 | ) === true
102 | ) {
103 | // files processing
104 | if ($elements['files']) {
105 | foreach ($elements['files'] as $file) {
106 | $this->zip->addFile(
107 | $this->pathPrefix . $file,
108 | basename($file)
109 | );
110 | }
111 | }
112 |
113 | // directories processing
114 | if ($elements['directories']) {
115 | $this->addDirs($elements['directories']);
116 | }
117 |
118 | $this->zip->close();
119 |
120 | return true;
121 | }
122 |
123 | return false;
124 | }
125 |
126 | /**
127 | * Archive extract
128 | *
129 | * @return bool
130 | */
131 | protected function extractArchive()
132 | {
133 | $zipPath = $this->pathPrefix . $this->request->input('path');
134 |
135 | $rootPath = dirname($zipPath);
136 |
137 | // extract to new folder
138 | $folder = $this->request->input('folder');
139 |
140 | if ($this->zip->open($zipPath) === true) {
141 | $this->zip->extractTo($folder ? $rootPath . '/' . $folder : $rootPath);
142 | $this->zip->close();
143 |
144 |
145 | return true;
146 | }
147 |
148 | return false;
149 | }
150 |
151 | /**
152 | * Add directories - recursive
153 | *
154 | * @param array $directories
155 | */
156 | protected function addDirs(array $directories)
157 | {
158 | foreach ($directories as $directory) {
159 |
160 | // Create recursive directory iterator
161 | $files = new RecursiveIteratorIterator(
162 | new RecursiveDirectoryIterator($this->pathPrefix . $directory, false),
163 | RecursiveIteratorIterator::LEAVES_ONLY
164 | );
165 |
166 | foreach ($files as $name => $file) {
167 | // Get real and relative path for current item
168 | $filePath = $file->getRealPath();
169 | $relativePath = substr(
170 | $filePath,
171 | strlen($this->fullPath($this->request->input('path')))
172 | );
173 |
174 | if (!$file->isDir()) {
175 | // Add current file to archive
176 | $this->zip->addFile($filePath, $relativePath);
177 | } else {
178 | // add empty folders
179 | if (!glob($filePath . '/*')) {
180 | $this->zip->addEmptyDir($relativePath);
181 | }
182 | }
183 | }
184 | }
185 | }
186 |
187 | /**
188 | * Create archive name with full path
189 | *
190 | * @return string
191 | */
192 | protected function createName()
193 | {
194 | return $this->fullPath($this->request->input('path'))
195 | . $this->request->input('name');
196 | }
197 |
198 | /**
199 | * Generate full path
200 | *
201 | * @param $path
202 | *
203 | * @return string
204 | */
205 | protected function fullPath($path)
206 | {
207 | return $path ? $this->pathPrefix . $path . '/' : $this->pathPrefix;
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/src/Services/DirectoryService.php:
--------------------------------------------------------------------------------
1 | model = new Directory();
21 | }
22 |
23 | public function listDirectories(Directory $directory, $recursive = false)
24 | {
25 | if ($recursive) {
26 | $dirs = collect($this->disk->allDirectories($directory->path));
27 | }
28 |
29 | $dirs = collect($this->disk->directories($directory->path));
30 |
31 | return $dirs;
32 | }
33 |
34 | public function listFiles(Directory $directory, $recursive = false)
35 | {
36 | if ($recursive) {
37 | $dirs = collect($this->disk->allFiles($directory->path));
38 | }
39 |
40 | $dirs = collect($this->disk->files($directory->path));
41 |
42 | return $dirs;
43 | }
44 |
45 | public function createDirectory(array $data)
46 | {
47 | $path = $this->base_directory . $this->ds . $data['name'];
48 |
49 | if (!checkPath($path, $this->disk_name)) {
50 | if ($this->disk->makeDirectory($path)) {
51 | DB::transaction(function () use ($data, $path) {
52 | $this->model->create([
53 | // 'user_id' => user()->id,
54 | 'name' => $data['name'],
55 | 'description' => $data['description'] ?? '',
56 | 'path' => $path,
57 | 'parent_id' => $data['parent_id'] ?? 0,
58 | 'disk' => $this->disk_name,
59 | ]);
60 | });
61 | return true;
62 | } else {
63 |
64 | // $this->error('Directory "' . $directory . '" already exists.');
65 | // $this->error('Can not create directory.');
66 | return false;
67 | }
68 | }
69 |
70 | return false;
71 | }
72 |
73 | public function renameDirectory(Directory $directory, $newName)
74 | {
75 | if ($directory->name == $newName) return false;
76 |
77 |
78 | $path = $this->base_directory . $this->ds . $directory->name;
79 |
80 | if ($this->disk->exists($path)) {
81 | DB::transaction(function () use ($directory, $newName) {
82 | $directory->update([
83 | 'name' => $newName
84 | ]);
85 | });
86 |
87 | if ($this->disk->move($directory->name, $newName)) return true;
88 | };
89 | return false;
90 | }
91 |
92 | public function deleteDirectory(Directory $directory)
93 | {
94 | $path = $directory->path;
95 |
96 | if (!checkPath($path, $this->disk_name)) {
97 | return false; // directory does not exists
98 | }
99 |
100 | $directoryFiles = array_merge($this->disk->directories($path), $this->disk->files($path));
101 | if ($directoryFiles)
102 | return false; // directory is not empty
103 |
104 | if ($this->disk->deleteDirectory($path)) {
105 | DB::transaction(function () use ($directory) {
106 | $directory->forceDelete();
107 | });
108 | return true;
109 | }
110 |
111 | return false;
112 | }
113 |
114 | /**
115 | * Return files and directories within a directory.
116 | *
117 | * @param string $directory
118 | *
119 | * @return array
120 | */
121 | public function directoryInfo(Directory $directory)
122 | {
123 | // Get the names of the sub directorys within this directory
124 | $subFolders = collect($this->disk->directories($directory->path))->reduce(function ($subFolders, $subFolder) {
125 | if (!$this->isItemHidden($subFolder)) {
126 | $subFolders[] = $this->directoryDetails($subFolder);
127 | }
128 |
129 | return $subFolders;
130 | }, collect([]));
131 |
132 | // Get all files within this directory
133 | $files = collect($this->disk->files($directory->path))->reduce(function ($files, $path) {
134 | if (!$this->isItemHidden($path)) {
135 | $files[] = $this->fileDetails($path);
136 | }
137 |
138 | return $files;
139 | }, collect([]));
140 |
141 | $itemsCount = $subFolders->count() + $files->count();
142 |
143 | return compact('directory', 'subFolders', 'files', 'itemsCount');
144 | }
145 |
146 | /**
147 | * Return an array of directory details for a given directory.
148 | *
149 | * @param $path
150 | *
151 | * @return array
152 | */
153 | public function directoryDetails($path)
154 | {
155 | $path = '/' . ltrim($path, '/');
156 |
157 | return [
158 | 'name' => basename($path),
159 | 'mime_type' => 'directory',
160 | 'disk_path' => $path,
161 | 'modified' => $this->lastModified($path),
162 | ];
163 | }
164 |
165 | /**
166 | * Return an array of file details for a given file.
167 | *
168 | * @param $path
169 | *
170 | * @return array
171 | */
172 | public function fileDetails($path)
173 | {
174 | $path = '/' . ltrim($path, '/');
175 |
176 | return [
177 | 'original_name' => $this->getOriginalNameFromPath($path),
178 | 'name' => basename($path),
179 | 'disk_path' => $path,
180 | 'url_path' => $this->disk->url($path),
181 | 'extension' => $this->getExtention($path),
182 | 'mime_type' => $this->getMime($path),
183 | 'size' => $this->disk->size($path),
184 | 'human_size' => $this->getHumanReadableSize($this->disk->size($path)),
185 | 'modified' => $this->lastModified($path),
186 | ];
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/config/filemanager.php:
--------------------------------------------------------------------------------
1 | env("FILEMANAGER_BASE_DIR", 'filemanager'),
7 |
8 | /**
9 | *
10 | * route configs that you want to use default work package
11 | *
12 | * The default group settings for the elFinder routes.
13 | * prefix result return => yourdomain.test/API_PREFIX/API_VERSION/FILE_MANAGER_PREFIX/
14 | *
15 | */
16 | 'routes' => [
17 | 'prefix' => env('FILEMANAGER_ROUTE_PREFIX', 'filemanger'),
18 | 'web' => [
19 | 'middleware' => ['web', 'auth'], //Set to empty to disable middleware filter
20 | ],
21 | 'api' => [
22 | 'api_prefix' => env('FILEMANAGER_API_PREFIX', 'api'),
23 | 'middleware' => ['api'], //Set to null to disable middleware filter
24 | ],
25 | ],
26 |
27 | 'database' => [
28 | // for track who work with filemanger (create directory, upload, ...)
29 | 'user_model' => \App\Models\User::class,
30 |
31 | 'files' => [
32 | 'table' => 'files',
33 | 'model' => \Miladimos\FileManager\Models\File::class,
34 | ],
35 | 'file_group_table' => [
36 | 'table' => 'file_groups'
37 | ],
38 | 'directories' => [
39 | 'table' => 'directories',
40 | 'model' => \Miladimos\FileManager\Models\Directory::class,
41 | ],
42 | ],
43 |
44 | /**
45 | * List of disk names that you want to use for upload
46 | *
47 | * local, public
48 | *
49 | */
50 | 'disk' => env('FILEMANAGER_DISK', 'local'),
51 |
52 | /**
53 | *
54 | * Default Locale
55 | * available locale : en - fa
56 | * for display views
57 | */
58 | 'locales' => [
59 | 'default' => env("FILEMANAGER_LOCALE", 'en'),
60 |
61 | 'en' => [
62 | 'title' => 'English',
63 | 'flag' => '',
64 | 'dir' => 'ltr',
65 | ],
66 |
67 | 'fa' => [
68 | 'title' => 'فارسی',
69 | 'flag' => '',
70 | 'dir' => 'rtl',
71 | ],
72 | ],
73 |
74 | 'download_link_expire' => '10', // in minute
75 |
76 | /**
77 | * The maximum upload file size of an item in bytes.
78 | * Adding a larger file will result in an exception.
79 | */
80 | 'max_file_size' => 1024 * 1024 * 10,
81 |
82 | 'max_image_width' => 1024,
83 |
84 | 'max_image_height' => 1024,
85 |
86 | 'image_quality' => 80,
87 |
88 | /**
89 | * strategies
90 | *
91 | * directory path template.
92 | * Variables:
93 | * - `Y` Year, example: 2021
94 | * - `m` Month, example: 04
95 | * - `d` Date, example: 08
96 | * - `H` Hour, example: 12
97 | * - `i` Minute, example: 15
98 | *
99 | * sizes in pixel
100 | */
101 | 'strategies' => [
102 | 'file' => [
103 | 'path' => 'files/{Y}/{m}/{d}/timestamp-$originalFilename',
104 | "date_time_prefix" => true, // before name : time_name.ext
105 | 'max_size' => '2m',
106 | ],
107 | 'thumbnail' => [
108 | 'path' => 'thumbnails/{Y}/{m}/{d}/timestamp-$originalFilename',
109 | "date_time_prefix" => false, // before name : time_name.ext
110 | 'height' => 60,
111 | 'width' => 60,
112 | 'fit' => 'stretch', // ['stretch', 'crop', 'contain', 'max', 'fill']
113 | 'max_size' => '2m',
114 | ],
115 | 'avatar' => [
116 | 'path' => 'thumbnails/{Y}/{m}/{d}/timestamp-$originalFilename',
117 | "date_time_prefix" => false, // before name : time_name.ext
118 | 'height' => 250,
119 | 'width' => 250,
120 | 'fit' => 'stretch', // ['stretch', 'crop', 'contain', 'max', 'fill']
121 | "sizes" => ["16", "24", "32", "64", "128", "320"],
122 | "thumb" => "320",
123 | 'max_size' => '2m',
124 | ],
125 | ],
126 |
127 | // for uploads
128 | 'allowed_mimes' => [
129 | 'image/gif',
130 | 'image/jpeg',
131 | 'image/png',
132 | 'image/bmp',
133 | 'image/png',
134 | 'image/tiff',
135 | 'application/json',
136 | 'application/x-tar',
137 | 'application/zip',
138 | ],
139 |
140 | // for uploads
141 | 'allowed_extensions' => [
142 | 'jpeg', 'jpg', 'png', 'gif', 'webp', 'docx',
143 | 'pdf', 'ttf', 'css', 'php', 'html', 'htm', 'js',
144 | 'xls', 'txt', 'xlsx', 'docx', 'pdf', 'rar', 'zip',
145 | 'mp4', 'mp3', 'csv', 'cv', 'tar', 'bz2',
146 | ],
147 |
148 | // for uploads
149 | 'disallow_extensions' => ['exe', 'asm', 'bin', 'o', 'jar'],
150 |
151 | /**
152 | * date() format for file modifications date
153 | * for created_at , updated_at, modified_at
154 | * Doc - https://www.php.net/manual/en/function.date.php
155 | * ex: d.m.y H:i
156 | * and you can use "ago" for ago human readable time ex: 10 minutes ago
157 | */
158 | 'datetime_format' => 'ago',
159 |
160 | /**
161 | * Show / Hide system files and folders
162 | */
163 | 'hiddenFiles' => false,
164 |
165 | // in views
166 | 'hide_files_extension' => false,
167 |
168 | 'pagination' => [
169 | 'folders' => 12, //2 rows
170 |
171 | 'files' => 15, //3 rows
172 | ],
173 |
174 | 'logger' => [
175 | 'active' => false,
176 | 'channel' => env("LOG_CHANNEL", "stack"),
177 | 'level' => 'info', // default level
178 | ],
179 |
180 | /**
181 | * Image cache ( Intervention Image Cache )
182 | *
183 | * set 0 - if you don't need cache (default)
184 | * if you want use cache - set the number of minutes for which the value should be cached
185 | */
186 | 'cache' => 0,
187 |
188 | /***************************************************************************
189 | * ACL rules list - used for default ACL repository (ConfigACLRepository)
190 | *
191 | * 1 it's user ID
192 | * null - for not authenticated user
193 | *
194 | * 'disk' => 'disk-name'
195 | *
196 | * 'path' => 'folder-name'
197 | * 'path' => 'folder1*' - select folder1, folder12, folder1/sub-folder, ...
198 | * 'path' => 'folder2/*' - select folder2/sub-folder,... but not select folder2 !!!
199 | * 'path' => 'folder-name/file-name.jpg'
200 | * 'path' => 'folder-name/*.jpg'
201 | *
202 | * * - wildcard
203 | *
204 | * access: 0 - deny, 1 - read, 2 - read/write
205 | */
206 | 'aclRules' => [
207 | null => [
208 | //['disk' => 'public', 'path' => '/', 'access' => 2],
209 | ],
210 | 1 => [
211 | //['disk' => 'public', 'path' => 'images/arch*.jpg', 'access' => 2],
212 | //['disk' => 'public', 'path' => 'files/*', 'access' => 1],
213 | ],
214 | ],
215 |
216 | ];
217 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/miladimos/laravel-filemanager/forks)
2 | [](https://github.com/miladimos/laravel-filemanager/stargazers)
3 |
4 | [comment]: <> (- [English](README-en.md))
5 |
6 | # Under Development
7 |
8 | ##### help us for development :)
9 |
10 | ### for installation in root of your project do these steps:
11 |
12 | ``` php
13 | composer require miladimos/laravel-filemanager
14 | ```
15 |
16 | 2. Open your config/app.php and add the following lines:
17 |
18 | ```php
19 | // in providers
20 | Miladimos\FileManager\Providers\FileManagerServiceProvider::class,
21 |
22 | // in aliases
23 | Miladimos\FileManager\Facades\FileManagerFacade::class,
24 | ```
25 |
26 | 3. Run the command below to install package:
27 |
28 | ```
29 | php artisan filemanager:install
30 | ```
31 |
32 | ### Configuration ! important !
33 |
34 | next go to the file
35 |
36 | ```php
37 | config/filemanager.php;
38 | ```
39 |
40 | for initialize file manager first set these confings:
41 |
42 | 1. set default storage to upload file (default is: local)
43 | 2. set base directory name for file manager (default is: filemanager/)
44 |
45 | and run bellow command for initialize:
46 |
47 | ``` php
48 | php artisan filemanager:init
49 | ```
50 |
51 | then create tables:
52 |
53 | ``` php
54 | php artisan migrate
55 | ```
56 |
57 | just it :)
58 |
59 | if you are set public disk run bellow command:
60 |
61 | ```php
62 | php artisan storage:link
63 | ```
64 |
65 | and if you want use ftp add these config in your config/filesystems.php:
66 |
67 | ```php
68 | 'ftp' => [
69 | 'driver' => 'ftp',
70 | 'host' => 'ftp.example.com',
71 | 'username' => 'your-username',
72 | 'password' => 'your-password',
73 |
74 | // Optional FTP Settings...
75 | // 'port' => 21,
76 | // 'root' => '',
77 | // 'passive' => true,
78 | // 'ssl' => true,
79 | // 'timeout' => 30,
80 | ],
81 | ```
82 |
83 | and for sftp use this:
84 |
85 | ```php
86 | 'sftp' => [
87 | 'driver' => 'sftp',
88 | 'host' => 'example.com',
89 | 'username' => 'your-username',
90 | 'password' => 'your-password',
91 |
92 | // Settings for SSH key based authentication...
93 | 'privateKey' => '/path/to/privateKey',
94 | 'password' => 'encryption-password',
95 |
96 | // Optional SFTP Settings...
97 | // 'port' => 22,
98 | // 'root' => '',
99 | // 'timeout' => 30,
100 | ],
101 | ```
102 |
103 | [comment]: <> (### نحوه استفاده)
104 |
105 | [comment]: <> (برای اپلود فایل:)
106 |
107 | [comment]: <> (```)
108 |
109 | [comment]: <> (public function store(Request $request))
110 |
111 | [comment]: <> ({ )
112 |
113 | [comment]: <> ( // This will upload your file to the default folder of selected in config storage)
114 |
115 | [comment]: <> ( UploadService::uploadFile($request->file('some_file'));)
116 |
117 | [comment]: <> ( // This will upload your file to the given as second parameter path of default storage)
118 |
119 | [comment]: <> ( UploadService::uploadFile($request->file('some_file'), 'path/to/upload');)
120 |
121 | [comment]: <> ( // This will upload your file to the given storage)
122 |
123 | [comment]: <> ( UploadService::uploadFile($request->file('some_file'), 'path/to/upload', 'storage_name');)
124 |
125 | [comment]: <> ( // This will also resize image to the given width and height)
126 |
127 | [comment]: <> ( UploadService::uploadFile($request->file('some_file'), 'path/to/upload', 'storage_name');)
128 |
129 | [comment]: <> (})
130 |
131 | [comment]: <> (```)
132 |
133 | [comment]: <> (برای آپلود عکس با فرمت base64:)
134 |
135 | [comment]: <> (```php)
136 |
137 | [comment]: <> (public function store(Request $request))
138 |
139 | [comment]: <> ({ )
140 |
141 | [comment]: <> ( // This will upload your file to the default folder of selected in config storage)
142 |
143 | [comment]: <> ( UploadService::uploadBase64Image($request->input('image'));)
144 |
145 | [comment]: <> ( // This will upload your file to the given as second parameter path of default storage)
146 |
147 | [comment]: <> ( UploadService::uploadFile($request->input('image'), 'path/to/upload');)
148 |
149 | [comment]: <> ( // This will upload your file to the given storage)
150 |
151 | [comment]: <> ( UploadService::uploadFile($request->input('image'), 'path/to/upload', 'storage_name');)
152 |
153 | [comment]: <> ( // This will also resize image to the given width and height)
154 |
155 | [comment]: <> ( UploadService::uploadFile($request->input('image'), 'path/to/upload', 'storage_name');)
156 |
157 | [comment]: <> (})
158 |
159 | [comment]: <> (```)
160 |
161 | ### Features ❤️
162 |
163 | #### You are free to use whatever you like 😎 ( you can just use services in your coding or use apis for your graphical file manager or whatever ...)
164 |
165 | ### Backend Services:
166 |
167 | ##### Directory service:
168 |
169 | ```php
170 | use Miladimos\FileManager\Services\DirectoryService;
171 |
172 | $service = new DirectoryService();
173 | $service->createDirectory($name); // name of directory for create
174 | $service->deleteDirectory($uuid); // uuid of directory for delete in db and disk
175 | $service->listDirectories($path) // list all directories in given path
176 | $service->listDirectoriesRecursive($path); // list all directories in given path Recursively
177 | ```
178 |
179 | ##### File service:
180 |
181 | ```php
182 | use Miladimos\FileManager\Services\FileService;
183 |
184 | $service = new FileService(); // or resolve(FileService::class)
185 | ```
186 |
187 | ##### FileGroup service:
188 |
189 | ```php
190 | use Miladimos\FileManager\Services\FileGroupService;
191 |
192 | $service = new FileGroupService();
193 | $service->allFileGroups();
194 | $service->createFileGroup(array $data); // $data = ['title', 'description']
195 | $service->updateFileGroup(FileGroup $fileGroup, array $data); // $data = ['title', 'description']
196 | $service->deleteFileGroup(FileGroup $fileGroup);
197 | ```
198 |
199 | ##### Image service:
200 |
201 | ```php
202 | use Miladimos\FileManager\Services\ImageService;
203 |
204 | $service = new ImageService();
205 | ```
206 |
207 | ##### Upload service:
208 |
209 | ```php
210 | use Miladimos\FileManager\Services\UploadService;
211 |
212 | $service = new UploadService();
213 | ```
214 |
215 | ### API over backend services:
216 |
217 | for all requests set these headers:
218 |
219 | Content-Type : application/x-www-form-urlencoded
220 |
221 | ```
222 | prefix = /api_prefix/filemanager_api_version/route_prefix
223 |
224 | // Directories
225 | POST -> prefix/directories // store new directory
226 | DELETE -> prefix/directories // receive directories field: it can be array of uuid or one uuid of directories for delete
227 |
228 |
229 | // File Groups
230 | GET -> prefix/filegroups // return all available file groups
231 | POST -> prefix/filegroups // store new file groups -> receive : title, description
232 | PUT -> prefix/filegroups/{filegroup}/update // update file groups -> receive : title, description
233 | DELETE -> prefix/filegroups/{filegroup} // delete file groups
234 | ```
235 |
236 | ### BACKEND TODO:
237 |
238 | - [x] Directory service - list, list recursive, create, delete, move
239 | - [ ] File service - list, delete, move
240 | - [ ] Upload service -
241 | - [ ] Image service -
242 | - [ ] FileGroup service -
243 | - [ ] Archive service - zip, tar
244 |
245 | ### FRONTEND TODO:
246 |
247 | - [ ] Web view -
248 |
--------------------------------------------------------------------------------
/src/Services/Service.php:
--------------------------------------------------------------------------------
1 | disk = Storage::disk(config('filemanager.disk'));
35 | $this->disk_name = config('filemanager.disk');
36 | $this->base_directory = config('filemanager.base_directory');
37 | $this->mimeDetect = new FinfoMimeTypeDetector();
38 | $this->loggerService = new LoggerService();
39 | }
40 |
41 | /**
42 | * Return the last modified time. If a timestamp can not be found fall back
43 | * to today's date and time...
44 | *
45 | * @param string $path
46 | *
47 | * @return Carbon
48 | */
49 | public function lastModified(string $path)
50 | {
51 | try {
52 | return Carbon::createFromTimestamp($this->disk->lastModified($path));
53 | } catch (\Exception $e) {
54 | return Carbon::now();
55 | }
56 | }
57 |
58 | /**
59 | * check storage path
60 | *
61 | * @param $src
62 | *
63 | * @return string
64 | */
65 | protected function getStorageFolder($src)
66 | {
67 | if ($this->disk_name == "storage")
68 | return storage_path($src);
69 | if ($this->disk_name == "public")
70 | return public_path($src);
71 | return public_path($src);
72 | }
73 |
74 | /**
75 | * Sanitize the directory name.
76 | *
77 | * @param $directory
78 | *
79 | * @return mixed
80 | */
81 | protected function cleanDirectoryName($directory)
82 | {
83 | return DIRECTORY_SEPARATOR . trim(str_replace('..', '', $directory), DIRECTORY_SEPARATOR);
84 | }
85 |
86 | /**
87 | * generate and unique & random name
88 | *
89 | * @param int $length
90 | * @return string
91 | */
92 | protected function generateRandomFileName(int $length = 10): string
93 | {
94 | do {
95 | $randomName = Str::random($length);
96 | $check = File::query()
97 | ->where("name", $randomName)
98 | ->first();
99 | } while (!empty($check));
100 |
101 | return $randomName;
102 | }
103 |
104 | /**
105 | * generate and unique & random name
106 | *
107 | * @param int $length
108 | * @return string
109 | */
110 | protected function generateRandomName(int $length = 10): string
111 | {
112 | $chars = range('a', 'z');
113 | $charsC = range('A', 'Z');
114 | $nums = range(1, 9) + 1;
115 |
116 | $merged = implode("", array_merge($chars, $charsC, $nums));
117 | $str = str_shuffle($merged);
118 | $randomName = Str::random(3) . substr($str, 0, $length);
119 |
120 | return $randomName;
121 | }
122 |
123 | protected function getHumanReadableSize(int $sizeInBytes): string
124 | {
125 | $units = ['B', 'KB', 'MB', 'GB', 'TB'];
126 |
127 | if ($sizeInBytes == 0) {
128 | return '0 ' . $units[1];
129 | }
130 |
131 | for ($i = 0; $sizeInBytes > 1024; $i++) {
132 | $sizeInBytes /= 1024;
133 | }
134 |
135 | return round($sizeInBytes, 2) . ' ' . $units[$i];
136 | }
137 |
138 | /**
139 | * Get content for the selected disk and path
140 | *
141 | * @param $disk
142 | * @param null $path
143 | *
144 | * @return array
145 | */
146 | protected function getContent($disk, $path = null)
147 | {
148 | $content = Storage::disk($disk)->listContents($path);
149 |
150 | // get a list of directories
151 | $directories = $this->filterDir($disk, $content);
152 |
153 | // get a list of files
154 | $files = $this->filterFile($disk, $content);
155 |
156 | return compact('directories', 'files');
157 | }
158 |
159 | /**
160 | * Get only directories
161 | *
162 | * @param $content
163 | *
164 | * @return array
165 | */
166 | protected function filterDir($disk, $content)
167 | {
168 | // select only dir
169 | $dirsList = Arr::where($content, function ($item) {
170 | return $item['type'] === 'dir';
171 | });
172 |
173 | // remove 'filename' param
174 | $dirs = array_map(function ($item) {
175 | return Arr::except($item, ['filename']);
176 | }, $dirsList);
177 |
178 | return array_values($dirs);
179 | }
180 |
181 | /**
182 | * Get only files
183 | *
184 | * @param $disk
185 | * @param $content
186 | *
187 | * @return array
188 | */
189 | protected function filterFile($disk, $content)
190 | {
191 | // select only files
192 | $files = Arr::where($content, function ($item) {
193 | return $item['type'] === 'file';
194 | });
195 |
196 | return array_values($files);
197 | }
198 |
199 | /**
200 | * Get directories for tree module
201 | *
202 | * @param $disk
203 | * @param $path
204 | *
205 | * @return array
206 | */
207 | protected function getDirectoriesTree($disk, $path = null)
208 | {
209 | $directories = $this->directoriesWithProperties($disk, $path);
210 |
211 | foreach ($directories as $index => $dir) {
212 | $directories[$index]['props'] = [
213 | 'hasSubdirectories' => Storage::disk($disk)
214 | ->directories($dir['path']) ? true : false,
215 | ];
216 | }
217 |
218 | return $directories;
219 | }
220 |
221 | /**
222 | * File properties
223 | *
224 | * @param $disk
225 | * @param null $path
226 | *
227 | * @return mixed
228 | */
229 | protected function fileProperties($disk, $path = null)
230 | {
231 | $file = $this->disk->getMetadata($path);
232 |
233 | $pathInfo = pathinfo($path);
234 |
235 | $file['basename'] = $pathInfo['basename'];
236 | $file['dirname'] = $pathInfo['dirname'] === '.' ? ''
237 | : $pathInfo['dirname'];
238 | $file['extension'] = isset($pathInfo['extension'])
239 | ? $pathInfo['extension'] : '';
240 | $file['filename'] = $pathInfo['filename'];
241 |
242 | return $file;
243 | }
244 |
245 | /**
246 | * Work out if an item (file or folder) is hidden (begins with a ".").
247 | *
248 | * @param $item
249 | *
250 | * @return bool
251 | */
252 | protected function isItemHidden($item)
253 | {
254 | return Str::startsWith(last(explode(DIRECTORY_SEPARATOR, $item)), '.');
255 | }
256 |
257 | public function generatePath($path)
258 | {
259 | return $path . DIRECTORY_SEPARATOR;
260 | }
261 |
262 | public function getMime($path)
263 | {
264 | $path = $this->disk->path($path);
265 | return $this->mimeDetect->detectMimeTypeFromFile($path) ?? 'unknown/type';
266 | }
267 |
268 | public function getExtention($path)
269 | {
270 | $path = $this->disk->path($path);
271 | return pathinfo($path)['extension'] ?? 'unknown';
272 | }
273 |
274 | public function getOriginalNameFromPath($path)
275 | {
276 | return substr(basename($path), strpos(basename($path), "-") + 1);
277 | }
278 | }
279 |
--------------------------------------------------------------------------------
/src/Services/UploadService.php:
--------------------------------------------------------------------------------
1 | directoryService = new DirectoryService();
30 |
31 | $this->fileModel = new File();
32 |
33 | $this->directoryModel = new Directory();
34 | }
35 |
36 | public function uploadFile(UploadedFile $uploadedFile, $directory_id = 0)
37 | {
38 | /// ProcessUpload::dispatch($upload, $key);
39 |
40 | $path = $this->directoryModel->find($directory_id)->path;
41 |
42 | if ($uploadedFile->isValid() && $this->fileExtIsAllowed($uploadedFile->getExtension())) {
43 |
44 | $year = Carbon::now()->year;
45 | $month = Carbon::now()->month;
46 | $day = Carbon::now()->day;
47 |
48 | $originalName = $uploadedFile->getClientOriginalName();
49 | $fileExt = $uploadedFile->getClientOriginalExtension();
50 | $mimeType = $uploadedFile->getClientMimeType();
51 | $fileSize = $uploadedFile->getSize(); // in bytes
52 |
53 | // $uploadPath = "{$path}{$this->ds}{$year}{$this->ds}{$month}{$this->ds}{$day}";
54 |
55 | // $this->mkdir_directory_if_not_exists($uploadPath);
56 |
57 | $finalFileName = Carbon::now()->timestamp . "-{$originalName}";
58 |
59 | $fullUploadedPath = $path . $this->ds . $finalFileName;
60 |
61 | if ($this->disk->put($fullUploadedPath, $uploadedFile->getContent())) {
62 | DB::transaction(function () use ($originalName, $finalFileName, $directory_id, $path, $fullUploadedPath, $fileSize, $mimeType, $fileExt) {
63 | $this->fileModel->create([
64 | 'original_name' => $originalName,
65 | 'name' => $finalFileName,
66 | 'disk' => $this->disk_name,
67 | 'directory_id' => $directory_id,
68 | // 'user_id' => user()->id,
69 | 'path' => $path,
70 | 'url' => url('storage/' . $fullUploadedPath),
71 | 'size' => $fileSize,
72 | 'mime_type' => $mimeType,
73 | 'extension' => $fileExt,
74 | ]);
75 | });
76 |
77 | return true;
78 | } else {
79 | return false;
80 | }
81 | }
82 |
83 | return false;
84 | }
85 |
86 | public function uploadImage(UploadedFile $uploadedFile, $directory_id = 0)
87 | {
88 | $path = $this->directoryModel->find($directory_id)->path;
89 |
90 | if ($uploadedFile->isValid() && $this->fileExtIsAllowed($uploadedFile->getClientOriginalExtension())) {
91 |
92 | $image = Image::make($uploadedFile->getRealPath());
93 | $year = Carbon::now()->year;
94 | $month = Carbon::now()->month;
95 | $day = Carbon::now()->day;
96 |
97 | $originalName = $uploadedFile->getClientOriginalName();
98 | $fileExt = $uploadedFile->getClientOriginalExtension();
99 | $mimeType = $uploadedFile->getClientMimeType();
100 | $fileSize = $uploadedFile->getSize();
101 |
102 | $uploadPath = "{$path}{$this->ds}{$year}{$this->ds}{$month}{$this->ds}{$day}";
103 |
104 | // $uploadPath = "{$path}{$this->ds}{$year}{$this->ds}{$month}{$this->ds}{$day}";
105 |
106 | // $this->mkdir_directory_if_not_exists($uploadPath);
107 |
108 | $finalFileName = Carbon::now()->timestamp . "-{$originalName}";
109 |
110 | $fullUploadedPath = $path . $this->ds . $finalFileName;
111 |
112 | event(new BeforeUpload());
113 |
114 | if ($this->disk->put($fullUploadedPath, $image->encode())) {
115 | DB::transaction(function () use ($originalName, $finalFileName, $directory_id, $path, $fullUploadedPath, $fileSize, $mimeType, $fileExt, $image) {
116 | $this->fileModel->create([
117 | 'original_name' => $originalName,
118 | 'name' => $finalFileName,
119 | 'disk' => $this->disk_name,
120 | 'directory_id' => $directory_id,
121 | // 'user_id' => user()->id,
122 | 'path' => $path,
123 | 'url' => url('storage/' . $fullUploadedPath),
124 | 'size' => $fileSize,
125 | 'mime_type' => $mimeType,
126 | 'extension' => $fileExt,
127 | 'width' => $image->width(),
128 | 'height' => $image->height(),
129 | ]);
130 | });
131 |
132 | event(new AfterUpload());
133 |
134 | return true;
135 | } else {
136 | return false;
137 | }
138 | }
139 |
140 | return false;
141 | }
142 |
143 | function mkdir_directory_if_not_exists($dirPath)
144 | {
145 | dd(explode("/", $dirPath));
146 | if (!checkPath($dirPath, $this->disk_name)) {
147 | $this->directoryService->createDirectory([]);
148 | }
149 | }
150 |
151 | // file extension is allowed from config
152 | public function fileExtIsAllowed($ext)
153 | {
154 | $exts = config('filemanager.allowed_extensions');
155 | return in_array($ext, $exts);
156 | }
157 |
158 | // file mime is allowed from config
159 | public function fileMimeIsAllowed($mime)
160 | {
161 | $mimes = config('filemanager.allowed_mimes');
162 | return in_array($mime, $mimes);
163 | }
164 |
165 | public function saveUploadedFiles(UploadedFile $files, $directory_id = 0)
166 | {
167 | $path = $this->directoryModel->find($directory_id)->path;
168 |
169 | return $files->getUploadedFiles()->reduce(function ($uploaded, UploadedFile $file) use ($path) {
170 | $fileName = $file->getClientOriginalName();
171 | if ($this->disk->exists($path . $fileName)) {
172 | // $this->errors[] = 'File ' . $path . $fileName . ' already exists in this folder.';
173 |
174 | return $uploaded;
175 | }
176 |
177 | if (!$file->storeAs($path, $fileName, [
178 | 'disk' => $this->diskName,
179 | 'visibility' => $this->access,
180 | ])) {
181 | // $this->errors[] = trans('media-manager::messages.upload_error', ['entity' => $fileName]);
182 |
183 | return $uploaded;
184 | }
185 | $uploaded++;
186 |
187 | return $uploaded;
188 | }, 0);
189 | }
190 |
191 | // public function uploadFileByUrl(string $url, string $field, $fileName = null)
192 | // {
193 | // $uuid = Str::uuid();
194 | // $file = file_get_contents($url);
195 | // $url = strtok($url, '?');
196 | // $config = config('upload.files.' . $field);
197 | //
198 | // $orignalName = str_replace('_', '-', pathinfo($url, PATHINFO_FILENAME));
199 | // $orignalName = str_replace(' ', '-', pathinfo($url, PATHINFO_FILENAME));
200 | // $extension = pathinfo($url, PATHINFO_EXTENSION);
201 | // $extension = ($extension) ? "." . $extension : $extension;
202 | // $storagePath = $this->disk->getDriver()->getAdapter()->getPathPrefix();
203 | //
204 | // if ($fileName) {
205 | // $fileNameWithExtension = $fileName . $extension;
206 | // $orignalName = $fileName;
207 | // } else {
208 | // $fileNameWithExtension = $orignalName . $extension;
209 | // }
210 | //
211 | // $this->disk->put('/uploads/' . $uuid . '/' . $fileNameWithExtension, $file);
212 | //
213 | // $mimeType = mime_content_type($storagePath . '/uploads/' . $uuid . '/' . $fileNameWithExtension);
214 | // $mimeFileType = $this->getFileType($mimeType);
215 | //
216 | // $file = $this->fileModel->create([
217 | // 'private' => array_get($config, 'private', false),
218 | // 'title' => $orignalName,
219 | // 'file_field' => $field,
220 | // 'file_name' => $fileNameWithExtension,
221 | // 'mime_type' => $mimeType,
222 | // 'file_type' => $mimeFileType,
223 | // 'size' => (filesize($storagePath . '/uploads/' . $uuid . '/' . $fileNameWithExtension) / 1024) / 1024,
224 | // 'uuid' => $uuid,
225 | // ]);
226 | //
227 | //
228 | // if ($mimeFileType != 'image' || !array_get($config, 'resize')) {
229 | // return true;
230 | // }
231 | //
232 | // foreach ($config['resize'] as $key => $value) {
233 | // if (array_get($value, 'create_on_upload', false)) {
234 | // $this->resizeImage($file, $key);
235 | // continue;
236 | // }
237 | //
238 | // ProcessUpload::dispatch($file, $key);
239 | // }
240 | //
241 | // return $file;
242 | // }
243 | }
244 |
--------------------------------------------------------------------------------
/src/Models/File.php:
--------------------------------------------------------------------------------
1 | 'int',
25 | ];
26 |
27 | public function user()
28 | {
29 | return $this->belongsTo(config('filemanager.database.user_model'), 'user_id');
30 | }
31 |
32 | public function groups()
33 | {
34 | return $this->belongsToMany(FileGroup::class, 'file_group_pivot');
35 | }
36 |
37 | public function fileable()
38 | {
39 | return $this->morphTo();
40 | }
41 |
42 | public function getFullUrl(string $conversionName = ''): string
43 | {
44 | return url($this->getUrl($conversionName));
45 | }
46 |
47 | public function getExtensionAttribute(): string
48 | {
49 | return pathinfo($this->file_name, PATHINFO_EXTENSION);
50 | }
51 |
52 | public function getHumanReadableSizeAttribute(): string
53 | {
54 | return File::getHumanReadableSize($this->size);
55 | }
56 |
57 | public function getDiskDriverName(): string
58 | {
59 | return strtolower(config("filesystems.disks.{$this->disk}.driver"));
60 | }
61 |
62 | public function getConversionsDiskDriverName(): string
63 | {
64 | $diskName = $this->conversions_disk ?? $this->disk;
65 |
66 | return strtolower(config("filesystems.disks.{$diskName}.driver"));
67 | }
68 |
69 | public function hasCustomProperty(string $propertyName): bool
70 | {
71 | return Arr::has($this->custom_properties, $propertyName);
72 | }
73 |
74 | /**
75 | * Get the value of custom property with the given name.
76 | *
77 | * @param string $propertyName
78 | * @param mixed $default
79 | *
80 | * @return mixed
81 | */
82 | public function getCustomProperty(string $propertyName, $default = null)
83 | {
84 | return Arr::get($this->custom_properties, $propertyName, $default);
85 | }
86 |
87 | /**
88 | * @param string $name
89 | * @param mixed $value
90 | *
91 | * @return $this
92 | */
93 | public function setCustomProperty(string $name, $value): self
94 | {
95 | $customProperties = $this->custom_properties;
96 |
97 | Arr::set($customProperties, $name, $value);
98 |
99 | $this->custom_properties = $customProperties;
100 |
101 | return $this;
102 | }
103 |
104 | public function forgetCustomProperty(string $name): self
105 | {
106 | $customProperties = $this->custom_properties;
107 |
108 | Arr::forget($customProperties, $name);
109 |
110 | $this->custom_properties = $customProperties;
111 |
112 | return $this;
113 | }
114 |
115 | public function getMediaConversionNames(): array
116 | {
117 | $conversions = ConversionCollection::createForMedia($this);
118 |
119 | return $conversions->map(fn (Conversion $conversion) => $conversion->getName())->toArray();
120 | }
121 |
122 | public function getGeneratedConversions(): Collection
123 | {
124 | return collect($this->generated_conversions ?? []);
125 | }
126 |
127 |
128 | public function markAsConversionGenerated(string $conversionName): self
129 | {
130 | $generatedConversions = $this->generated_conversions;
131 |
132 | Arr::set($generatedConversions, $conversionName, true);
133 |
134 | $this->generated_conversions = $generatedConversions;
135 |
136 | $this->save();
137 |
138 | return $this;
139 | }
140 |
141 | public function markAsConversionNotGenerated(string $conversionName): self
142 | {
143 | $generatedConversions = $this->generated_conversions;
144 |
145 | Arr::set($generatedConversions, $conversionName, false);
146 |
147 | $this->generated_conversions = $generatedConversions;
148 |
149 | $this->save();
150 |
151 | return $this;
152 | }
153 |
154 | public function hasGeneratedConversion(string $conversionName): bool
155 | {
156 | $generatedConversions = $this->getGeneratedConversions();
157 |
158 | return $generatedConversions[$conversionName] ?? false;
159 | }
160 |
161 | public function toResponse($request)
162 | {
163 | return $this->buildResponse($request, 'attachment');
164 | }
165 |
166 | public function toInlineResponse($request)
167 | {
168 | return $this->buildResponse($request, 'inline');
169 | }
170 |
171 | private function buildResponse($request, string $contentDispositionType)
172 | {
173 | $downloadHeaders = [
174 | 'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
175 | 'Content-Type' => $this->mime_type,
176 | 'Content-Length' => $this->size,
177 | 'Content-Disposition' => $contentDispositionType . '; filename="' . $this->file_name . '"',
178 | 'Pragma' => 'public',
179 | ];
180 |
181 | return response()->stream(function () {
182 | $stream = $this->stream();
183 |
184 | fpassthru($stream);
185 |
186 | if (is_resource($stream)) {
187 | fclose($stream);
188 | }
189 | }, 200, $downloadHeaders);
190 | }
191 |
192 | public function getResponsiveImageUrls(string $conversionName = ''): array
193 | {
194 | return $this->responsiveImages($conversionName)->getUrls();
195 | }
196 |
197 | public function hasResponsiveImages(string $conversionName = ''): bool
198 | {
199 | return count($this->getResponsiveImageUrls($conversionName)) > 0;
200 | }
201 |
202 | public function getSrcset(string $conversionName = ''): string
203 | {
204 | return $this->responsiveImages($conversionName)->getSrcset();
205 | }
206 |
207 | public function getPreviewUrlAttribute()
208 | {
209 | return $this->hasGeneratedConversion('preview') ? $this->getUrl('preview') : '';
210 | }
211 |
212 | public function getOriginalUrlAttribute()
213 | {
214 | return $this->getUrl();
215 | }
216 |
217 | public function move(HasMedia $model, $collectionName = 'default', string $diskName = '', string $fileName = ''): self
218 | {
219 | $newMedia = $this->copy($model, $collectionName, $diskName, $fileName);
220 |
221 | $this->delete();
222 |
223 | return $newMedia;
224 | }
225 |
226 | public function copy(HasMedia $model, $collectionName = 'default', string $diskName = '', string $fileName = ''): self
227 | {
228 | $temporaryDirectory = TemporaryDirectory::create();
229 |
230 | $temporaryFile = $temporaryDirectory->path('/') . DIRECTORY_SEPARATOR . $this->file_name;
231 |
232 | /** @var \Spatie\MediaLibrary\MediaCollections\Filesystem $filesystem */
233 | $filesystem = app(Filesystem::class);
234 |
235 | $filesystem->copyFromMediaLibrary($this, $temporaryFile);
236 |
237 | $fileAdder = $model
238 | ->addMedia($temporaryFile)
239 | ->usingName($this->name)
240 | ->setOrder($this->order_column)
241 | ->withCustomProperties($this->custom_properties);
242 |
243 | if ($fileName !== '') {
244 | $fileAdder->usingFileName($fileName);
245 | }
246 |
247 | $newMedia = $fileAdder
248 | ->toMediaCollection($collectionName, $diskName);
249 |
250 | $temporaryDirectory->delete();
251 |
252 | return $newMedia;
253 | }
254 |
255 | public function responsiveImages(string $conversionName = ''): RegisteredResponsiveImages
256 | {
257 | return new RegisteredResponsiveImages($this, $conversionName);
258 | }
259 |
260 | public function stream()
261 | {
262 | /** @var \Spatie\MediaLibrary\MediaCollections\Filesystem $filesystem */
263 | $filesystem = app(Filesystem::class);
264 |
265 | return $filesystem->getStream($this);
266 | }
267 |
268 | public function toHtml()
269 | {
270 | return $this->img()->toHtml();
271 | }
272 |
273 | public function img(string $conversionName = '', $extraAttributes = []): HtmlableMedia
274 | {
275 | return (new HtmlableMedia($this))
276 | ->conversion($conversionName)
277 | ->attributes($extraAttributes);
278 | }
279 |
280 | public function __invoke(...$arguments): HtmlableMedia
281 | {
282 | return $this->img(...$arguments);
283 | }
284 |
285 | public function temporaryUpload(): BelongsTo
286 | {
287 | MediaLibraryPro::ensureInstalled();
288 |
289 | return $this->belongsTo(TemporaryUpload::class);
290 | }
291 |
292 | public static function findWithTemporaryUploadInCurrentSession(array $uuids)
293 | {
294 | MediaLibraryPro::ensureInstalled();
295 |
296 | return static::query()
297 | ->whereIn('uuid', $uuids)
298 | ->whereHasMorph(
299 | 'model',
300 | [TemporaryUpload::class],
301 | fn (Builder $builder) => $builder->where('session_id', session()->getId())
302 | )
303 | ->get();
304 | }
305 |
306 |
307 | public function setNameAttribute($value)
308 | {
309 | $this->attributes['name'] = now() . '-' . $value;
310 | }
311 |
312 | public function getCreatedAtAttribute($value)
313 | {
314 | return Carbon::parse($value)->diffForHumans();
315 | }
316 |
317 | public function getUpdatedAtAttribute($value)
318 | {
319 | return Carbon::parse($value)->diffForHumans();
320 | }
321 |
322 | /**
323 | * generate the link for download file
324 | * this link has expire time
325 | *
326 | * @return string
327 | */
328 | public function generateDownloadLink()
329 | {
330 | $secret = env('APP_KEY');
331 |
332 | $expireTime = (int)config('filemanager.download_link_expire');
333 |
334 | $timestamp = Carbon::now()->addMinutes($expireTime)->timestamp;
335 | $hash = Hash::make($secret . $this->uuid . getUserIP() . $timestamp);
336 |
337 | // return "/api/filemanager/download/$this->uuid?mac=$hash&t=$timestamp";
338 | return route('filemanager.download', [$this, $hash, $timestamp]);
339 | }
340 |
341 | public function getPublicUrl($key = null)
342 | {
343 | $storageDisk = Storage::disk(config('filemanager.disk'));
344 | $url = $storageDisk->url('uploads/' . $this->uuid . '/' . $this->file_name);
345 | if (config('filemanager.files.' . $key)) {
346 | list($key, $resize, $size) = explode('.', $key);
347 | $extension = pathinfo($this->file_name, PATHINFO_EXTENSION);
348 | $name = str_replace('.' . $extension, '', $this->file_name);
349 | $url = $storageDisk->url('cache/' . $this->uuid . '/' . $name . '-' . $size . '.' . $extension);
350 | }
351 |
352 | return $url;
353 | }
354 |
355 | public function getIsPrivateAttribute()
356 | {
357 | return $this->is_private ? true : false;
358 | }
359 |
360 | public function getIsPublicAttribute()
361 | {
362 | return $this->is_private ? false : true;
363 | }
364 |
365 | public function getBasenameAttribute(): string
366 | {
367 | return $this->name . '.' . $this->extension;
368 | }
369 |
370 | public function __toString()
371 | {
372 | return "name: {$this->name}, size: {$this->size}, mime: {$this->mimeType}";
373 | }
374 | }
375 |
--------------------------------------------------------------------------------
/src/Services/ImageService.php:
--------------------------------------------------------------------------------
1 | sizes = config('filemanager.images.sizes');
19 | }
20 |
21 | protected function handleDelete(File $file)
22 | {
23 | if (is_null($this->getSizes())) {
24 | if ($sizes = $this->getConfig("sizes"))
25 | $this->setSizes($sizes);
26 | else
27 | $this->setSizes(["16", "24", "32", "64", "128"]);
28 | }
29 |
30 | if (is_null($this->getThumbSize())) {
31 | if (!$thumb = $this->getConfig("thumb"))
32 | $this->setThumbSize($thumb);
33 | else
34 | $this->setThumbSize("128");
35 | }
36 |
37 | $sizes = $this->getSizes();
38 | foreach ($sizes as $size) {
39 | $sizePath = $file->base_path . "{$size}/";
40 | $sizePath = $sizePath . $file->file_name;
41 | if ($file->private) {
42 | $sizePath = storage_path($sizePath);
43 | } else {
44 | $sizePath = public_path($sizePath);
45 | }
46 |
47 | $this->disk->delete($sizePath);
48 | }
49 |
50 | $thumbSize = $file->base_path . "thumb/" . $file->file_name;
51 | $originalSize = $file->base_path . "original/" . $file->file_name;
52 |
53 | if ($file->private) {
54 | $thumbSize = storage_path($thumbSize);
55 | } else {
56 | $thumbSize = public_path($thumbSize);
57 | }
58 |
59 | if ($file->private) {
60 | $originalSize = storage_path($originalSize);
61 | } else {
62 | $originalSize = public_path($originalSize);
63 | }
64 |
65 | $this->disk->delete($thumbSize);
66 | $this->disk->delete($originalSize);
67 |
68 | return true;
69 | }
70 |
71 | /**
72 | * Crop the image (called via ajax).
73 | */
74 | public function getCropimage($overWrite = true)
75 | {
76 | $image_name = request('img');
77 | $image_path = $this->lfm->setName($image_name)->path('absolute');
78 | $crop_path = $image_path;
79 |
80 | if (!$overWrite) {
81 | $fileParts = explode('.', $image_name);
82 | $fileParts[count($fileParts) - 2] = $fileParts[count($fileParts) - 2] . '_cropped_' . time();
83 | $crop_path = $this->lfm->setName(implode('.', $fileParts))->path('absolute');
84 | }
85 |
86 | event(new ImageIsCropping($image_path));
87 |
88 | $crop_info = request()->only('dataWidth', 'dataHeight', 'dataX', 'dataY');
89 |
90 | // crop image
91 | Image::make($image_path)
92 | ->crop(...array_values($crop_info))
93 | ->save($crop_path);
94 |
95 | // make new thumbnail
96 | $this->lfm->makeThumbnail($image_name);
97 |
98 | event(new ImageWasCropped($image_path));
99 | }
100 |
101 | public function getNewCropimage()
102 | {
103 | $this->getCropimage(false);
104 | }
105 |
106 |
107 |
108 | //public function resizeImagePost(Request $request)
109 | //{
110 | // $this->validate($request, [
111 | // 'title' => 'required',
112 | // 'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
113 | // ]);
114 | //
115 | // $image = $request->file('image');
116 | // $input['imagename'] = time().'.'.$image->getClientOriginalExtension();
117 | //
118 | // $destinationPath = public_path('/thumbnail');
119 | // $img = Image::make($image->getRealPath());
120 | // $img->resize(100, 100, function ($constraint) {
121 | // $constraint->aspectRatio();
122 | // })->save($destinationPath.'/'.$input['imagename']);
123 | //
124 | // $destinationPath = public_path('/images');
125 | // $image->move($destinationPath, $input['imagename']);
126 | //
127 | // $this->postImage->add($input);
128 | //
129 | // return back()
130 | // ->with('success','Image Upload successful')
131 | // ->with('imageName',$input['imagename']);
132 | //}
133 |
134 |
135 | public function makeImage(Image $image, array $sizeOption)
136 | {
137 | $sizeOption += [
138 | 'width' => null,
139 | 'height' => null,
140 | 'fit' => null,
141 | ];
142 |
143 | if (!$sizeOption['fit']) {
144 | return $image->resize($sizeOption['width'], $sizeOption['height'], function ($constraint) {
145 | $constraint->aspectRatio();
146 | $constraint->upsize();
147 | });
148 | }
149 |
150 | if ($sizeOption['fit'] == 'crop') {
151 | $cropX = isset($sizeOption['x']) ? $sizeOption['x'] : null;
152 | $cropY = isset($sizeOption['y']) ? $sizeOption['y'] : null;
153 |
154 | $image->crop($sizeOption['width'], $sizeOption['height'], $cropX, $cropY, function ($constraint) {
155 | $constraint->upsize();
156 | });
157 | } elseif ($sizeOption['fit'] == 'max') {
158 | $image->resize($sizeOption['width'], $sizeOption['height'], function ($constraint) {
159 | $constraint->upsize();
160 | });
161 | } elseif ($sizeOption['fit'] == 'contain') {
162 | $image->resizeCanvas($sizeOption['width'], $sizeOption['height']);
163 | } elseif ($sizeOption['fit'] == 'stretch') {
164 | $image->resize($sizeOption['width'], $sizeOption['height'], function ($constraint) {
165 | $constraint->upsize();
166 | });
167 | } elseif ($sizeOption['fit'] == 'pad') {
168 | $width = $image->width();
169 | $height = $image->height();
170 |
171 | $color = isset($sizeOption['color']) ? $sizeOption['color'] : '#fff';
172 | if ($width < $height) {
173 | $newHeight = $sizeOption['height'];
174 | $newWidth = ($width * 100) / $sizeOption['width'];
175 |
176 | $image->resize($newWidth, $newHeight, function ($constraint) {
177 | $constraint->aspectRatio();
178 | });
179 | $image->resizeCanvas($sizeOption['width'], $sizeOption['height'], 'center', false, $color);
180 | } elseif ($width > $height) {
181 | $newWidth = $sizeOption['width'];
182 | $newHeight = ($height * 100) / $sizeOption['height'];
183 |
184 | $image->resize($newWidth, $newHeight, function ($constraint) {
185 | $constraint->aspectRatio();
186 | });
187 | $image->resizeCanvas($sizeOption['width'], $sizeOption['height'], 'center', false, $color);
188 | } elseif ($width == $height) {
189 | $image->resize($sizeOption['width'], $sizeOption['height'], function ($constraint) {
190 | $constraint->aspectRatio();
191 | });
192 | $image->resizeCanvas($sizeOption['width'], $sizeOption['height'], 'center', false, $color);
193 | }
194 | } else {
195 | $image->fit($sizeOption['width'], $sizeOption['height'], function ($constraint) {
196 | $constraint->upsize();
197 | });
198 | }
199 |
200 | return $image;
201 | }
202 |
203 | public function resizeImage(Upload $upload, string $size)
204 | {
205 | $storage = \Storage::disk(config('upload.disk'));
206 | $config = config('upload.files.' . $upload->file_field . '.resize.' . $size);
207 | $path = $upload->uuid . '/';
208 | $file = $storage->get('uploads/' . $path . $upload->file_name);
209 |
210 | $extension = pathinfo($upload->file_name, PATHINFO_EXTENSION);
211 | $name = str_replace('.' . $extension, '', $upload->file_name);
212 |
213 | $image = \Image::make($file);
214 | $image = $this->makeImage($image, $config);
215 | $image->encode($extension);
216 | $storage->put('cache/' . $path . $name . '-' . $size . '.' . $extension, $image->__toString());
217 | }
218 |
219 |
220 | public function generateImages($fileField = null)
221 | {
222 | $uploads = Upload::query()
223 | ->where('has_reference', true)
224 | ->where('file_type', 'image')
225 | ->where(function ($query) use ($fileField) {
226 | if ($fileField) {
227 | $query->where('file_field', $fileField);
228 | }
229 | })
230 | ->get();
231 |
232 | foreach ($uploads as $upload) {
233 | foreach (config('upload.files.' . $upload->file_field . '.resize') as $size => $options) {
234 | $this->resizeImage($upload, $size);
235 | }
236 | }
237 | }
238 |
239 | public function optimizeUploadedImages($fileField = null)
240 | {
241 | $storage = \Storage::disk(config('upload.disk'));
242 |
243 | $uploads = Upload::query()
244 | ->where('file_type', 'image')
245 | ->where(function ($query) use ($fileField) {
246 | if ($fileField) {
247 | $query->where('file_field', $fileField);
248 | }
249 | })
250 | ->get();
251 |
252 | foreach ($uploads as $upload) {
253 | foreach ($storage->allFiles('uploads/' . $upload->uuid) as $file) {
254 | ImageOptimizer::optimize($storage->path($file));
255 | }
256 |
257 | foreach ($storage->allFiles('cache/' . $upload->uuid) as $file) {
258 | ImageOptimizer::optimize($storage->path($file));
259 | }
260 | }
261 | }
262 |
263 | public function optimizeImages($path)
264 | {
265 | $images = ['jpg', 'jpeg', 'png', 'gif', 'svg'];
266 | $path = base_path($path);
267 |
268 | if (!is_dir($path)) {
269 | throw new \Exception('Directory Not found.');
270 | }
271 |
272 | $files = \File::allfiles($path);
273 |
274 | foreach ($files as $file) {
275 | //optimize images only
276 | if (!in_array(strtolower($file->getExtension()), $images)) {
277 | continue;
278 | }
279 |
280 | ImageOptimizer::optimize($file->getRealPath());
281 | }
282 | }
283 |
284 |
285 | /**
286 | * resize image and return specific array of images
287 | *
288 | * @param $filePath
289 | * @param $uploadPath
290 | * @param $fileName
291 | * @return mixed
292 | */
293 | protected function resize($filePath, $uploadPath, $fileName)
294 | {
295 | if (is_null($this->getSizes())) {
296 | if ($sizes = $this->getConfig("sizes"))
297 | $this->setSizes($sizes);
298 | else
299 | $this->setSizes(["16", "24", "32", "64", "128"]);
300 | }
301 |
302 | if (is_null($this->getThumbSize())) {
303 | if (!$thumb = $this->getConfig("thumb"))
304 | $this->setThumbSize($thumb);
305 | else
306 | $this->setThumbSize("128");
307 | }
308 |
309 | $sizes = $this->getSizes();
310 | foreach ($sizes as $size) {
311 | $sizeUploadPath = $uploadPath . "{$size}/";
312 | if (!is_dir($sizeUploadPath)) mkdir($sizeUploadPath);
313 | $sizeName = $sizeUploadPath . $fileName;
314 | \Intervention\Image\Facades\Image::make($filePath)->fit($size, $size, function ($constraint) {
315 | $constraint->aspectRatio();
316 | // $constraint->upsize();
317 | })->save($sizeName);
318 | }
319 |
320 | $thumbUploadPath = $uploadPath . "thumb/";
321 | if (!is_dir($thumbUploadPath)) mkdir($thumbUploadPath);
322 | $thumbPath = $thumbUploadPath . $fileName;
323 | copy($uploadPath . "{$this->getThumbSize()}/" . $fileName, $thumbPath);
324 |
325 | return $this;
326 | }
327 |
328 | public function preview($disk, $path)
329 | {
330 | // get image
331 | $preview = Image::make($this->disk($disk)->get($path));
332 |
333 | return $preview->response();
334 | }
335 |
336 |
337 | public function url($disk, $path)
338 | {
339 | return [
340 | 'result' => [
341 | 'status' => 'success',
342 | 'message' => null,
343 | ],
344 | 'url' => $this->disk->disk($disk)->url($path),
345 | ];
346 | }
347 |
348 | // use Spatie\Image\Image;
349 |
350 | // class ImageFactory
351 | // {
352 | // public static function load(string $path): Image
353 | // {
354 | // return Image::load($path)->useImageDriver(config('media-library.image_driver'));
355 | // }
356 | // }
357 |
358 | //
359 | //class ImageRequest extends FormRequest
360 | //{
361 | // use ConvertsBase64ToFiles;
362 | //
363 | // protected function base64FileKeys(): array
364 | // {
365 | // return [
366 | // 'jpg_image' => 'Logo.jpg',
367 | // ];
368 | // }
369 | //
370 | // public function rules()
371 | // {
372 | // return [
373 | // 'jpg_image' => ['required', 'file', 'image'],
374 | // ];
375 | // }
376 | //}
377 | //
378 | //
379 | //trait ConvertsBase64ToFiles
380 | //{
381 | // protected function base64FileKeys(): array
382 | // {
383 | // return [];
384 | // }
385 | //
386 | // /**
387 | // * Pulls the Base64 contents for each image key and creates
388 | // * an UploadedFile instance from it and sets it on the
389 | // * request.
390 | // *
391 | // * @return void
392 | // */
393 | // function prepareForValidation()
394 | // {
395 | // Collection::make($this->base64FileKeys())->each(function ($filename, $key) {
396 | // rescue(function () use ($key, $filename) {
397 | // $base64Contents = $this->input($key);
398 | //
399 | // if (!$base64Contents) {
400 | // return;
401 | // }
402 | //
403 | // // Generate a temporary path to store the Base64 contents
404 | // $tempFilePath = tempnam(sys_get_temp_dir(), $filename);
405 | //
406 | // // Store the contents using a stream, or by decoding manually
407 | // if (Str::startsWith($base64Contents, 'data:') && count(explode(',', $base64Contents)) > 1) {
408 | // $source = fopen($base64Contents, 'r');
409 | // $destination = fopen($tempFilePath, 'w');
410 | //
411 | // stream_copy_to_stream($source, $destination);
412 | //
413 | // fclose($source);
414 | // fclose($destination);
415 | // } else {
416 | // file_put_contents($tempFilePath, base64_decode($base64Contents, true));
417 | // }
418 | //
419 | // $uploadedFile = new UploadedFile($tempFilePath, $filename, null, null, true);
420 | //
421 | // $this->request->remove($key);
422 | // $this->files->set($key, $uploadedFile);
423 | // }, null, false);
424 | // });
425 | // }
426 | }
427 |
--------------------------------------------------------------------------------