PluginProbe
Fluent Support – Helpdesk & Customer Support Ticket System / 2.2.0
Fluent Support – Helpdesk & Customer Support Ticket System v2.2.0
2.4.0 2.3.2 2.3.1 2.3.0 2.2.1 2.2.0 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.4.0 1.4.1 1.4.2 1.4.5 1.4.6 1.4.7 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 All 68 releases
fluent-support / app / Http / Controllers / UploaderController.php

UploaderController.php in Fluent Support – Helpdesk & Customer Support Ticket System 2.2.0, at app/Http/Controllers/UploaderController.php

250 lines 8.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentSupport\App\Http\Controllers;
4
5 use FluentSupport\App\Models\Attachment;
6 use FluentSupport\App\Models\Ticket;
7 use FluentSupport\App\Services\EmailNotification\Settings;
8 use FluentSupport\App\Services\Helper;
9 use FluentSupport\Framework\Http\Request\Request;
10 use FluentSupport\App\Services\Includes\UploadService;
11
12 /**
13 * UploaderController class is responsible for uploading file
14 * @package FluentSupport\App\Http\Controllers
15 *
16 * @version 1.0.0
17 */
18 class UploaderController extends Controller
19 {
20 /**
21 * uploadTicketFiles method will upload all the attached file in a ticket
22 * @param Request $request
23 * @return array[]
24 * @throws \FluentSupport\Framework\Validator\ValidationException
25 */
26 public function uploadTicketFiles(Request $request)
27 {
28 $settings = (new Settings())->globalBusinessSettings();
29 $maxFileSize = floatval($settings['max_file_size']);
30 $mimeHeadings = Helper::getAcceptedMimeHeadings();
31 $maxSizeBytes = $maxFileSize * 1024;
32 $imageType = $request->type ? $request->type : null;
33
34 $this->validateUploadedFiles($request->files(), $maxSizeBytes, $mimeHeadings, $maxFileSize);
35 $ticketId = $this->resolveTicketId($request);
36 $person = $this->resolvePerson($ticketId, $request);
37
38 $this->checkPermissionToUploadFile($person);
39
40 try {
41 $uploadedFiles = UploadService::handleTempFileUpload($request->files());
42 } catch (\Exception $e) {
43 return $this->sendError([
44 'message' => Helper::getSafeErrorMessage($e),
45 ]);
46 }
47
48 if (is_wp_error($uploadedFiles)) {
49 return $this->sendError([
50 'message' => $uploadedFiles->get_error_message(),
51 ]);
52 }
53
54 $attachmentHashes = $this->createAttachmentRecords($uploadedFiles, $ticketId, $person, $imageType);
55
56 return [
57 'attachments' => $attachmentHashes,
58 ];
59 }
60
61 private function validateUploadedFiles($files, $maxSizeBytes, $mimeHeadings, $maxFileSize)
62 {
63 $validationRules = [
64 'file' => 'max:' . $maxSizeBytes . '|mimetypes:' . implode(',', Helper::ticketAcceptedFileMiles()),
65 ];
66
67 $validationMessages = [
68 // translators: %s is a comma-separated list of allowed file types (e.g., "jpg, png, pdf")
69 'file.mimetypes' => sprintf(__('Only %s files are allowed.', 'fluent-support'), implode(', ', $mimeHeadings)),
70 // translators: %.01f is the maximum file size in megabytes
71 'file.max' => sprintf(__('The file cannot be more than %.01fMB. Please upload somewhere like Dropbox/Google Drive and paste the link in the response', 'fluent-support'), $maxFileSize),
72 ];
73
74 $this->validate($files, $validationRules, $validationMessages);
75 }
76
77 private function resolveTicketId($request)
78 {
79 $ticketId = $request->getSafe('ticket_id', 'intval');
80
81 if ($ticketId == 'undefined' || !$ticketId) {
82 return null;
83 }
84
85 if (Helper::getCurrentAgent()) {
86 return $ticketId;
87 }
88
89 $ticket = Ticket::wherePublicIdentifier($ticketId)->first();
90
91 return $ticket ? $ticket->id : null;
92 }
93
94 private function resolvePerson($ticketId, Request $request)
95 {
96 $agent = Helper::getCurrentAgent();
97 if ($agent) {
98 return $agent;
99 }
100
101 if ($ticketId && Helper::isPublicSignedTicketEnabled()) {
102 $intendedTicketHash = $request->getSafe('intended_ticket_hash', 'sanitize_text_field');
103 if ($intendedTicketHash && $intendedTicketHash != 'undefined') {
104 $ticket = Ticket::with(['customer'])
105 ->where('hash', $intendedTicketHash)
106 ->wherePublicIdentifier($ticketId)
107 ->first();
108
109 if ($ticket && $ticket->customer) {
110 return $ticket->customer;
111 }
112 }
113 }
114
115 return Helper::getCurrentPerson();
116 }
117
118 private function checkPermissionToUploadFile($person)
119 {
120 if (!$person) {
121 return $this->sendError([
122 'message' => __('You do not have permission to upload a file', 'fluent-support'),
123 ]);
124 }
125
126 if ($person->person_type === 'customer') {
127 $disabledFields = apply_filters('fluent_support/disabled_ticket_fields', []);
128 if (in_array('file_upload', $disabledFields)) {
129 return $this->sendError([
130 'message' => __('You do not have permission to upload a file', 'fluent-support'),
131 ]);
132 }
133 }
134 }
135
136 private function createAttachmentRecords($uploadedFiles, $ticketId, $person, $imageType)
137 {
138 $attachments = [];
139 $directPasteUrl = null;
140
141 foreach ($uploadedFiles as $file) {
142 if (empty($file['file_path'])) continue;
143
144 $fileData = [
145 'ticket_id' => intval($ticketId) ?: NULL,
146 'person_id' => intval($person->id),
147 'file_type' => $file['type'],
148 'file_path' => $file['file_path'],
149 'full_url' => esc_url($file['url']),
150 'title' => sanitize_file_name($file['name']),
151 'driver' => 'local',
152 'status' => 'in-active',
153 'settings' => [
154 'local_temp_path' => $file['file_path'],
155 ]
156 ];
157
158 try {
159 $attachment = Attachment::create($fileData);
160 $attachments[] = $attachment->file_hash;
161
162 if ($imageType == 'direct_paste') {
163 $directPasteUrl = $attachment->secureUrl;
164 }
165
166 do_action('fluent_support/attachment_uploaded_as_temp', $attachment, $ticketId);
167 $driver = Helper::getUploadDriverKey();
168
169 do_action_ref_array('fluent_support/attachment_uploaded_as_temp_' . $driver, [&$attachment, $ticketId]);
170 } catch (\Exception $exception) {
171 continue;
172 }
173 }
174
175 return $imageType == 'direct_paste' ? $directPasteUrl : $attachments;
176 }
177
178 public function uploadImage(Request $request)
179 {
180 $images = $request->files();
181 $ticketId = $this->resolveTicketId($request);
182
183 $validationError = $this->isValidImageType($images);
184 if ($validationError) {
185 return $validationError;
186 }
187
188 try {
189 $uploadedFiles = UploadService::handleUploadToLocal($ticketId, $images);
190 } catch (\Exception $e) {
191 return $this->sendError([
192 'message' => Helper::getSafeErrorMessage($e),
193 ]);
194 }
195
196 return [
197 'images' => $uploadedFiles,
198 ];
199 }
200
201 private function isValidImageType($images)
202 {
203 if (empty($images['image'])) {
204 return $this->sendError([
205 'message' => __('No image file provided.', 'fluent-support'),
206 ]);
207 }
208
209 $file = $images['image'];
210 $tempPath = $file->getPathname();
211 $extension = strtolower($file->getClientOriginalExtension());
212 $allowedExtensions = ['gif', 'ief', 'jpeg', 'jpg', 'webp', 'pjpeg', 'ktx', 'png'];
213
214 if (!in_array($extension, $allowedExtensions)) {
215 return $this->sendError([
216 'message' => __('Invalid image file type.', 'fluent-support'),
217 ]);
218 }
219
220 $allowedMimes = Helper::getMimeGroups()['images']['mimes'];
221 $realMime = $this->detectMimeType($tempPath);
222
223 if (!$realMime || !in_array($realMime, $allowedMimes)) {
224 return $this->sendError([
225 'message' => __('File content does not match the image type.', 'fluent-support'),
226 ]);
227 }
228
229 return null;
230 }
231
232 private function detectMimeType($filePath)
233 {
234 if (function_exists('finfo_open')) {
235 $finfo = finfo_open(FILEINFO_MIME_TYPE);
236 $mime = finfo_file($finfo, $filePath);
237 finfo_close($finfo);
238 return $mime;
239 }
240
241 if (function_exists('mime_content_type')) {
242 return mime_content_type($filePath);
243 }
244
245 // getimagesize works for standard image formats as last resort
246 $imageInfo = @getimagesize($filePath);
247 return $imageInfo ? $imageInfo['mime'] : false;
248 }
249 }
250