Issues (96)

src/Support/ClamavFileUpload.php (5 issues)

1
<?php
2
3
namespace Ikechukwukalu\Clamavfileupload\Support;
4
5
use Ikechukwukalu\Clamavfileupload\Models\FileUpload as FileUploadModel;
6
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
7
use Illuminate\Support\Facades\Storage;
8
use Ikechukwukalu\Clamavfileupload\Events\FileScanPass;
9
use Ikechukwukalu\Clamavfileupload\Events\FileScanFail;
10
use Ikechukwukalu\Clamavfileupload\Trait\ClamAV;
11
use Ikechukwukalu\Clamavfileupload\Foundation\FileUpload;
12
13
abstract class ClamavFileUpload extends FileUpload
14
{
15
    use ClamAV;
16
17
    /**
18
     * Run files scan and upload.
19
     *
20
     * @param  array $settings
21
     * @return  \Ikechukwukalu\Clamavfileupload\Models\FileUpload
22
     * @return  \Illuminate\Database\Eloquent\Collection
23
     * @return  bool
24
     */
25
    abstract protected function runFileUpload(array $settings = []): bool|FileUploadModel|EloquentCollection;
26
27
    /**
28
     * Run files scan and upload.
29
     *
30
     * @return  \Ikechukwukalu\Clamavfileupload\Models\FileUpload
31
     * @return  \Illuminate\Database\Eloquent\Collection
32
     * @return  bool
33
     */
34
    public function fileUpload(): bool|FileUploadModel|EloquentCollection
35
    {
36
        if($this->request->file()) {
37
            if (!$this->storeFiles()) {
38
                return $this->failedUpload(trans('clamavfileupload::clamav.failed'));
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->failedUplo...pload::clamav.failed')) returns the type false which is incompatible with the documented return type Ikechukwukalu\Clamavfileupload\Models\FileUpload.
Loading history...
39
            }
40
41
            if (!$this->areFilesSafe()) {
42
                return $this->removeFiles();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->removeFiles() returns the type boolean which is incompatible with the documented return type Ikechukwukalu\Clamavfileupload\Models\FileUpload.
Loading history...
43
            }
44
45
            if (is_array($this->request->file($this->input))) {
46
                return $this->insertMultipleFiles();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->insertMultipleFiles() returns the type Illuminate\Database\Eloquent\Collection|boolean which is incompatible with the documented return type Ikechukwukalu\Clamavfileupload\Models\FileUpload.
Loading history...
47
            }
48
49
            return $this->insertSingleFile();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->insertSingleFile() also could return the type boolean which is incompatible with the documented return type Ikechukwukalu\Clamavfileupload\Models\FileUpload.
Loading history...
50
        }
51
52
        $this->failedUpload(trans('clamavfileupload::clamav.empty_file_input'));
53
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type Ikechukwukalu\Clamavfileupload\Models\FileUpload.
Loading history...
54
    }
55
56
    /**
57
     * Scan file.
58
     *
59
     * @param $filePath
60
     * @param $file
61
     * @return  array
62
     */
63
    public function scanFile($filePath, $file): array
64
    {
65
        $data = [
66
            'ref' => $this->ref,
67
            'status' => false
68
        ];
69
70
        if ($this->ping()) {
71
            $data['status'] = $this->scan($filePath);
72
        }
73
74
        $data['message'] = str_replace($filePath,
75
                            $file->getClientOriginalName(),
76
                            $this->getMessage());
77
78
        if ($this->getMessage() == 'OK') {
79
            $data['errorFile'] = null;
80
            $data['error'] = null;
81
82
            return $data;
83
        }
84
85
        $data['errorFile'] = $file;
86
        $data['error'] = $this->getMessage();
87
        $this->failedUpload($data['error']);
88
89
        return $data;
90
    }
91
92
    /**
93
     * Are files safe.
94
     *
95
     * @return  bool
96
     */
97
    private function areFilesSafe(): bool
98
    {
99
        if (is_array($this->request->file($this->input))) {
100
            return $this->areMultipleFilesSafe();
101
        }
102
103
        return $this->isSingleFileSafe();
104
    }
105
106
    /**
107
     * Is single file safe.
108
     *
109
     * @return  bool
110
     */
111
    private function isSingleFileSafe(): bool
112
    {
113
        [$fileName, $relativeFilePath] = $this->fileNameAndPath();
114
        $storageDisk = $this->storageDisk();
115
116
        if (in_array($this->getDisk(), config('clamavfileupload.s3_disks'))) {
117
            [$storageDisk, $relativeFilePath] =
118
                $this->getTempDiskAndPath();
119
        }
120
121
        $this->scanData = $this->scanFile($storageDisk->path($relativeFilePath),
122
                                $this->request->file($this->input));
123
124
        if ($this->scanData['status']) {
125
            FileScanPass::dispatch($this->scanData);
126
            return true;
127
        }
128
129
        $this->logScanData($this->scanData['error']);
130
        FileScanFail::dispatch($this->scanData);
131
132
        return false;
133
    }
134
135
    /**
136
     * Are multiple files safe.
137
     *
138
     * @return  bool
139
     */
140
    private function areMultipleFilesSafe(): bool
141
    {
142
        $i = 1;
143
        $storageDisk = $this->storageDisk();
144
145
        foreach ($this->request->file($this->input) as $file) {
146
            [$fileName, $relativeFilePath] = $this->fileNameAndPath($file, $i);
147
148
            if (in_array($this->getDisk(), config('clamavfileupload.s3_disks'))
149
            ) {
150
                [$storageDisk, $relativeFilePath] =
151
                    $this->getTempDiskAndPath($file);
152
            }
153
154
            $this->scanData = $this->scanFile($storageDisk->path($relativeFilePath),
155
                                $file);
156
157
            if (!$this->scanData['status']) {
158
                $this->logScanData($this->scanData['error']);
159
                FileScanFail::dispatch($this->scanData);
160
161
                return false;
162
            }
163
164
            $i ++;
165
        }
166
167
        FileScanPass::dispatch($this->scanData);
168
        return true;
169
    }
170
171
    private function getTempDiskAndPath(mixed $file = null): array
172
    {
173
        if (!$file) {
174
            $file = $this->request->file($this->input);
175
        }
176
177
        $storageDisk = Storage::disk('local');
178
        $ary = explode('/', $file->getRealPath());
179
        $relativeFilePath = 'tmp/' . array_pop($ary);
180
181
        return [$storageDisk, $relativeFilePath];
182
    }
183
}
184