PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.5.0
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.5.0
2.10.0 2.10.01 2.9.1 2.9.0 2.8.1 2.8.0 2.7.7 2.7.5 2.7.0 2.6.01 2.6.0 2.5.0 2.4.01 trunk 1.0.90 1.0.91 1.0.92 1.0.93 1.0.94 1.0.95 1.0.96 1.0.97 1.0.98 1.0.99 1.1.0 All 77 releases
fluent-community / app / Services / UploadHelper.php

UploadHelper.php in FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses 2.5.0, at app/Services/UploadHelper.php

283 lines 10.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCommunity\App\Services;
4
5 use FluentCommunity\App\Models\Media;
6 use FluentCommunity\App\Services\Libs\FileSystem;
7 use FluentCommunity\Framework\Support\Arr;
8 use FluentCommunity\Framework\Validator\Validator;
9
10 class UploadHelper
11 {
12 public function processUpload($requestFiles, $options = [])
13 {
14 $defaultOptions = [
15 'max_size' => 10,
16 'size_unit' => 'MB',
17 'disable_convert' => 'no',
18 'resize' => true,
19 'max_width' => 0,
20 'context' => '',
21 'skip_convert' => ''
22 ];
23
24 $options = wp_parse_args($options, $defaultOptions);
25
26 $allowedTypes = implode(
27 ',',
28 apply_filters('fluent_community/support_attachment_types', [
29 'image/jpeg',
30 'image/pjpeg',
31 'image/jpeg',
32 'image/pjpeg',
33 'image/png',
34 'image/gif',
35 'image/webp'
36 ])
37 );
38
39 $maxFileUnit = apply_filters('fluent_community/media_upload_max_file_unit', $options['size_unit']);
40 $maxFileSize = apply_filters('fluent_community/media_upload_max_file_size', $options['max_size']);
41
42 $allowedFileSize = $maxFileSize;
43 if (strtoupper($maxFileUnit) == 'MB') {
44 $allowedFileSize = $maxFileSize * 1024;
45 } else if (strtoupper($maxFileUnit) == 'GB') {
46 $allowedFileSize = $maxFileSize * 1024 * 1024;
47 }
48
49 $validator = new Validator([
50 'file' => $requestFiles
51 ], );
52
53 $validator->validate($requestFiles, [
54 'file' => 'mimetypes:' . $allowedTypes . '|max:' . $allowedFileSize,
55 ], [
56 'file.mimetypes' => __('The file must be an image type.', 'fluent-community'),
57 /* translators: %$1s is replaced by the maximum allowed file size, %2$s is replaced by the file size unit (e.g. MB) */
58 'file.max' => sprintf(__('The file size must be less than %1$s%2$s.', 'fluent-community'), $maxFileSize, $maxFileUnit)
59 ]);
60
61 if ($validator->fails()) {
62 return new \WP_Error('validation_error', __('Validation Error', 'fluent-community'), $validator->errors());
63 }
64
65 add_filter('wp_handle_upload', [$this, 'fixImageOrientation']);
66 $uploadedFiles = FileSystem::put($requestFiles);
67 remove_filter('wp_handle_upload', [$this, 'fixImageOrientation']);
68
69 $file = $uploadedFiles[0];
70
71 $upload_dir = wp_upload_dir();
72
73 $originalUrl = $file['url'];
74 $orginalPath = $upload_dir['basedir'] . '/fluent-community/' . $file['file'];
75 $originalFileType = $file['type'];
76 $originalFileName = $file['file'];
77
78 $willWebPConvert = Arr::get($options, 'disable_convert') != 'yes';
79
80 $willWebPConvert = apply_filters('fluent_community/convert_image_to_webp', $willWebPConvert, $file);
81 $willResize = Arr::get($options, 'resize') != 'yes';
82 $maxWidth = Arr::get($options, 'max_width', 0);
83
84 $willResize = apply_filters('fluent_community/media_upload_resize', $willResize, $file);
85
86 if ($context = Arr::get($options, 'context')) {
87 $maxWidth = apply_filters('fluent_community/media_upload_max_width_' . $context, $maxWidth, $file);
88 }
89
90 if ($willResize && $maxWidth) {
91 $upload_dir = wp_upload_dir();
92 $fileUrl = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $file['url']);
93
94 $editor = wp_get_image_editor($fileUrl);
95
96 if (!is_wp_error($editor) && $editor->get_size()['width'] > $maxWidth) {
97 // Current file extension
98 $ext = pathinfo($file['url'], PATHINFO_EXTENSION);
99 $imageExtensions = ['jpg', 'jpeg', 'png', 'gif'];
100 $willConvert = in_array($ext, $imageExtensions) && $willWebPConvert;
101
102 if ($willConvert) {
103 $imageExtensions = array_map(function ($ext) {
104 return '.' . $ext;
105 }, $imageExtensions);
106
107 $fileUrl = str_replace($imageExtensions, '.webp', $fileUrl);
108 $file['file'] = str_replace($imageExtensions, '.webp', $file['file']);
109 $file['url'] = str_replace($imageExtensions, '.webp', $file['url']);
110 $file['type'] = 'image/webp';
111 }
112
113 // resize the image
114 $editor->resize($maxWidth, null, false);
115 $editor->set_quality(90);
116 if ($willConvert) {
117 $result = $editor->save($fileUrl, 'image/webp');
118 if ($result['mime-type'] == 'image/webp') {
119 // remove original file now
120 wp_delete_file(str_replace('.webp', '.' . $ext, $fileUrl));
121 }
122 $file['is_converted'] = true;
123 } else {
124 $result = $editor->save($fileUrl);
125 }
126
127 if ($result['mime-type'] != 'image/webp') {
128 $file['file'] = $originalFileName;
129 $file['url'] = $originalUrl;
130 $file['type'] = $result['mime-type'];
131 }
132
133 $file['meta'] = [
134 'width' => $editor->get_size()['width'],
135 'height' => $editor->get_size()['height']
136 ];
137 }
138 $file['path'] = $upload_dir['basedir'] . '/fluent-community/' . $file['file'];
139 } else {
140 $upload_dir = wp_upload_dir();
141 $file['path'] = $upload_dir['basedir'] . '/fluent-community/' . $file['file'];
142 }
143
144 if ($willWebPConvert && empty($file['is_converted']) && !Arr::get($options, 'skip_convert')) {
145 $path = $file['path'];
146 $extension = pathinfo($path, PATHINFO_EXTENSION);
147
148 $convertFromExtensions = ['png', 'jpg', 'jpeg', 'gif'];
149 if ($extension != 'webp' && in_array($extension, $convertFromExtensions)) {
150 // Let's convert to webp
151 $editor = wp_get_image_editor($file['path']);
152 if (!is_wp_error($editor)) {
153 $file['path'] = str_replace('.' . $extension, '.webp', $file['path']);
154 $file['url'] = str_replace('.' . $extension, '.webp', $file['url']);
155 $file['type'] = 'image/webp';
156 $result = $editor->save($file['path'], 'image/webp');
157
158 if ($result['mime-type'] != 'image/webp') {
159 $file['path'] = $orginalPath;
160 $file['url'] = $originalUrl;
161 $file['type'] = $result['mime-type'];
162 } else {
163 wp_delete_file($orginalPath);
164 }
165
166 $file['meta'] = [
167 'width' => $editor->get_size()['width'],
168 'height' => $editor->get_size()['height']
169 ];
170 }
171 }
172 }
173
174 $mediaData = [
175 'media_type' => $file['type'],
176 'driver' => 'local',
177 'media_path' => $file['path'],
178 'media_url' => $file['url'],
179 'settings' => Arr::get($file, 'meta', [])
180 ];
181
182 $mediaData = apply_filters('fluent_community/media_upload_data', $mediaData, $file);
183
184 if (is_wp_error($mediaData)) {
185 return $mediaData;
186 }
187
188 if (!$mediaData) {
189 return new \WP_Error('upload_error', __('Upload cancelled by a filter', 'fluent-community'));
190 }
191
192 // Let's create the media now
193 $media = Media::create($mediaData);
194
195 $mediaUrl = $media->public_url;
196
197 $mediaUrl = add_query_arg([
198 'media_key' => $media->media_key,
199 ], $mediaUrl);
200
201 return [
202 'url' => $mediaUrl,
203 'media_key' => $media->media_key,
204 'type' => $media->media_type,
205 'width' => Arr::get($media->settings, 'width'),
206 'height' => Arr::get($media->settings, 'height')
207 ];
208 }
209
210 public function fixImageOrientation($file)
211 {
212 // Only process JPEG images (since they typically have EXIF data)
213 $image_types = array('image/jpeg', 'image/jpg');
214 if (!in_array($file['type'], $image_types)) {
215 return $file;
216 }
217
218 // Check if the EXIF extension is available
219 if (!function_exists('exif_read_data')) {
220 return $file;
221 }
222
223 // Read EXIF data from the uploaded image
224 $exif = @exif_read_data($file['file']);
225
226 if (!$exif || !isset($exif['Orientation'])) {
227 return $file;
228 }
229
230 $orientation = $exif['Orientation'];
231
232 // Load the image based on the available library (Imagick or GD)
233 if (extension_loaded('imagick') && class_exists('Imagick')) {
234 // Use Imagick if available
235 try {
236 $image = new \Imagick($file['file']);
237 switch ($orientation) {
238 case 3: // 180°
239 $image->rotateImage(new \ImagickPixel(), 180);
240 break;
241 case 6: // 90° clockwise
242 $image->rotateImage(new \ImagickPixel(), 90);
243 break;
244 case 8: // 90° counter-clockwise
245 $image->rotateImage(new \ImagickPixel(), -90);
246 break;
247 }
248 // Strip EXIF data to prevent further issues
249 $image->stripImage();
250 // Save the rotated image
251 $image->writeImage($file['file']);
252 $image->destroy();
253 } catch (\Exception $e) {
254
255 }
256 } elseif (function_exists('imagecreatefromjpeg')) {
257 // Use GD if Imagick is not available
258 $image = @imagecreatefromjpeg($file['file']);
259 if ($image === false) {
260 return $file;
261 }
262
263 switch ($orientation) {
264 case 3: // 180°
265 $image = imagerotate($image, 180, 0);
266 break;
267 case 6: // 90° clockwise
268 $image = imagerotate($image, -90, 0);
269 break;
270 case 8: // 90° counter-clockwise
271 $image = imagerotate($image, 90, 0);
272 break;
273 }
274
275 // Save the rotated image
276 imagejpeg($image, $file['file'], 100);
277 imagedestroy($image);
278 }
279
280 return $file;
281 }
282 }
283