FileTrait   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 157
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 16
eloc 66
c 2
b 0
f 0
dl 0
loc 157
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A checkForDuplicate() 0 18 4
A getChunk() 0 32 2
A checkForFile() 0 9 3
A saveFile() 0 7 1
A cleanFilename() 0 5 1
A moveStoredFile() 0 24 3
A deleteFile() 0 23 2
1
<?php
2
3
namespace App\Traits;
4
5
use Illuminate\Http\UploadedFile;
6
use Pion\Laravel\ChunkUpload\Handler\HandlerFactory;
7
use Pion\Laravel\ChunkUpload\Receiver\FileReceiver;
8
9
use App\Models\FileUploads;
10
use Illuminate\Database\QueryException;
11
use Illuminate\Support\Facades\Log;
12
use Illuminate\Support\Facades\Auth;
13
use Illuminate\Support\Facades\Storage;
14
15
/**
16
 * File Trait assists with processing uploading and moving files
17
 */
18
trait FileTrait
19
{
20
    protected $disk;
21
    protected $folder;
22
23
    /**
24
     * Get an uploaded file chunk and process it
25
     */
26
    protected function getChunk($request)
27
    {
28
        $receiver = new FileReceiver('file', $request, HandlerFactory::classFromRequest($request));
29
        $save     = $receiver->receive();
30
31
        //  Save a completed upload
32
        if($save->isFinished())
33
        {
34
            $this->disk   = $request->disk;
35
            $this->folder = $request->folder;
36
            $filename     = $this->saveFile($save->getFile());
37
38
            $status = [
39
                'percent'  => 100,
40
                'complete' => true,
41
                'filename' => $filename,
42
                'disk'     => $request->disk,
43
                'folder'   => $request->folder,
44
            ];
45
46
            Log::debug('File Upload Completed.  Details - ', $status);
47
            return $status;
48
        }
49
50
        $handler = $save->handler();
51
        $status  = [
52
            'percent'  => $handler->getPercentageDone(),
53
            'complete' => false,
54
        ];
55
56
        Log::debug('File upload in progress.  Details - ', $status);
57
        return $status;
58
    }
59
60
    /**
61
     * Save the file to the file system
62
     */
63
    protected function saveFile(UploadedFile $file)
64
    {
65
        $properName = $this->cleanFilename($file->getClientOriginalName());
66
        $fileName   = $this->checkForDuplicate($properName);
67
68
        $file->storeAs($this->folder, $fileName, $this->disk);
69
        return $fileName;
70
    }
71
72
    /**
73
     * Sanitize the filename to remove any spaces or illegal characters
74
     */
75
    protected function cleanFilename($name)
76
    {
77
        $newName = str_replace(' ', '_', preg_replace("([^\w\s\d\-_~,;\[\]\(\).])", '', $name));
78
79
        return $newName;
80
    }
81
82
    /**
83
     * Check if the filename already exists.  If it does, append the filename with (number)
84
     */
85
    protected function checkForDuplicate($name)
86
    {
87
88
        if(Storage::disk($this->disk)->exists($this->folder.DIRECTORY_SEPARATOR.$name))
89
        {
90
            $parts = pathinfo($name);
91
            $ext   = isset($parts['extension']) ? ('.'.$parts['extension']) : '';
92
            $base  = $parts['filename'];
93
            $number = 0;
94
95
96
            do
97
            {
98
                $name = $base.'('.++$number.')'.$ext;
99
            } while(Storage::disk($this->disk)->exists($this->folder.DIRECTORY_SEPARATOR.$name));
100
        }
101
102
        return $name;
103
    }
104
105
    /**
106
     * Make sure that there is some file data in the users current session - abort if it is missing
107
     */
108
    protected function checkForFile()
109
    {
110
        if(!session()->has('new-file-upload'))
111
        {
112
            Log::critical('File upload information missing', [
113
                'route' => \Request::route()->getName(),
114
                'user'  => Auth::check() ? Auth::user()->username : \Request::ip(),
115
            ]);
116
            abort(500, 'Uploaded File Data Missing');
117
        }
118
    }
119
120
    /**
121
     * Move a file from one location to another and store new location in database
122
     */
123
    protected function moveStoredFile($fileId, $newFolder, $newDisk = null)
124
    {
125
        $file = FileUploads::find($fileId);
126
127
        $this->disk   = $newDisk !== null ? $newDisk : $file->disk;
128
        $this->folder = $newFolder;
129
130
        //  Verify the file actually exists
131
        if(!Storage::disk($file->disk)->exists($file->folder.DIRECTORY_SEPARATOR.$file->file_name))
132
        {
133
            return false;
134
        }
135
136
        //  Verify file is not duplicate and move
137
        $newName = $this->checkForDuplicate($file->file_name);
138
        Storage::disk($this->disk)->move($file->folder.DIRECTORY_SEPARATOR.$file->file_name, $this->folder.DIRECTORY_SEPARATOR.$newName);
139
140
        //  Update the database
141
        $file->file_name = $newName;
142
        $file->folder    = $this->folder;
143
        $file->disk      = $this->disk;
144
        $file->save();
145
146
        return true;
147
    }
148
149
    /**
150
     * Determine if a file is no longer in use, and then delete it from the filesystem
151
     */
152
    protected function deleteFile($fileID)
153
    {
154
        $fileData = FileUploads::find($fileID);
155
        $file     = $fileData->only(['disk', 'folder', 'file_name']);
156
157
        Log::debug('Attempting to delete file', $fileData->toArray());
158
159
        //  Try to delete the file from the database, if it fails, the file is in use elsewhere
160
        try
161
        {
162
            $fileData->delete();
163
        }
164
        catch(QueryException $e)
165
        {
166
            Log::debug('File ID '.$fileID.' is still in use and cannot be deleted');
167
            return false;
168
        }
169
170
        //  Delete the file from file storage
171
        Log::alert('File '.$file['folder'].DIRECTORY_SEPARATOR.$file['file_name'].' has been deleted');
172
        Storage::disk($file['disk'])->delete($file['folder'].DIRECTORY_SEPARATOR.$file['file_name']);
173
174
        return true;
175
    }
176
}
177