| @@ -45,15 +45,13 @@ | ||
| 45 | 45 | } else if (strtoupper($maxFileUnit) == 'GB') { |
| 46 | 46 | $allowedFileSize = $maxFileSize * 1024 * 1024; |
| 47 | 47 | } |
| 48 | 48 | |
| 49 | - $validator = new Validator([ | |
| 50 | - 'file' => $requestFiles | |
| 51 | - ], ); | |
| 52 | - | |
| 53 | - $validator->validate($requestFiles, [ | |
| 54 | - 'file' => 'mimetypes:' . $allowedTypes . '|max:' . $allowedFileSize, | |
| 49 | + // messages belong on the constructor: Validator::validate() takes only data and rules | |
| 50 | + $validator = Validator::make($requestFiles, [ | |
| 51 | + 'file' => 'required|mimetypes:' . $allowedTypes . '|max:' . $allowedFileSize, | |
| 55 | 52 | ], [ |
| 53 | + 'file.required' => __('No upload file was received. Please try again.', 'fluent-community'), | |
| 56 | 54 | 'file.mimetypes' => __('The file must be an image type.', 'fluent-community'), |
| 57 | 55 | /* translators: %$1s is replaced by the maximum allowed file size, %2$s is replaced by the file size unit (e.g. MB) */ |
| 58 | 56 | 'file.max' => sprintf(__('The file size must be less than %1$s%2$s.', 'fluent-community'), $maxFileSize, $maxFileUnit) |
| 59 | 57 | ]); |
| @@ -61,14 +59,22 @@ | ||
| 61 | 59 | if ($validator->fails()) { |
| 62 | 60 | return new \WP_Error('validation_error', __('Validation Error', 'fluent-community'), $validator->errors()); |
| 63 | 61 | } |
| 64 | 62 | |
| 65 | - add_filter('wp_handle_upload', [$this, 'fixImageOrientation']); | |
| 63 | + add_filter('wp_handle_upload', [self::class, 'fixImageOrientation']); | |
| 66 | 64 | $uploadedFiles = FileSystem::put($requestFiles); |
| 67 | - remove_filter('wp_handle_upload', [$this, 'fixImageOrientation']); | |
| 65 | + remove_filter('wp_handle_upload', [self::class, 'fixImageOrientation']); | |
| 68 | 66 | |
| 69 | - $file = $uploadedFiles[0]; | |
| 67 | + $file = Arr::get($uploadedFiles, 0); | |
| 70 | 68 | |
| 69 | + if (is_wp_error($file)) { | |
| 70 | + return $file; | |
| 71 | + } | |
| 72 | + | |
| 73 | + if (!is_array($file) || empty($file['url']) || empty($file['file']) || empty($file['type'])) { | |
| 74 | + return new \WP_Error('upload_error', __('No upload file was received. Please try again.', 'fluent-community')); | |
| 75 | + } | |
| 76 | + | |
| 71 | 77 | $upload_dir = wp_upload_dir(); |
| 72 | 78 | |
| 73 | 79 | $originalUrl = $file['url']; |
| 74 | 80 | $orginalPath = $upload_dir['basedir'] . '/fluent-community/' . $file['file']; |
| @@ -206,9 +212,9 @@ | ||
| 206 | 212 | 'height' => Arr::get($media->settings, 'height') |
| 207 | 213 | ]; |
| 208 | 214 | } |
| 209 | 215 | |
| 210 | - public function fixImageOrientation($file) | |
| 216 | + public static function fixImageOrientation($file) | |
| 211 | 217 | { |
| 212 | 218 | // Only process JPEG images (since they typically have EXIF data) |
| 213 | 219 | $image_types = array('image/jpeg', 'image/jpg'); |
| 214 | 220 | if (!in_array($file['type'], $image_types)) { |
| @@ -228,23 +234,46 @@ | ||
| 228 | 234 | } |
| 229 | 235 | |
| 230 | 236 | $orientation = $exif['Orientation']; |
| 231 | 237 | |
| 232 | - // Load the image based on the available library (Imagick or GD) | |
| 238 | + // Nothing to correct for the "normal" orientation | |
| 239 | + if ($orientation == 1) { | |
| 240 | + return $file; | |
| 241 | + } | |
| 242 | + | |
| 243 | + // Bake rotation into pixels before WebP conversion strips EXIF (else 2/4/5/7 render sideways) | |
| 233 | 244 | if (extension_loaded('imagick') && class_exists('Imagick')) { |
| 234 | 245 | // Use Imagick if available |
| 235 | 246 | try { |
| 236 | 247 | $image = new \Imagick($file['file']); |
| 248 | + $bg = new \ImagickPixel(); | |
| 237 | 249 | switch ($orientation) { |
| 250 | + case 2: // mirror horizontal | |
| 251 | + $image->flopImage(); | |
| 252 | + break; | |
| 238 | 253 | case 3: // 180° |
| 239 | - $image->rotateImage(new \ImagickPixel(), 180); | |
| 254 | + $image->rotateImage($bg, 180); | |
| 240 | 255 | break; |
| 256 | + case 4: // mirror vertical | |
| 257 | + $image->flipImage(); | |
| 258 | + break; | |
| 259 | + case 5: // transpose (mirror vertical + 90° clockwise) | |
| 260 | + $image->flipImage(); | |
| 261 | + $image->rotateImage($bg, 90); | |
| 262 | + break; | |
| 241 | 263 | case 6: // 90° clockwise |
| 242 | - $image->rotateImage(new \ImagickPixel(), 90); | |
| 264 | + $image->rotateImage($bg, 90); | |
| 243 | 265 | break; |
| 266 | + case 7: // transverse (mirror horizontal + 90° clockwise) | |
| 267 | + $image->flopImage(); | |
| 268 | + $image->rotateImage($bg, 90); | |
| 269 | + break; | |
| 244 | 270 | case 8: // 90° counter-clockwise |
| 245 | - $image->rotateImage(new \ImagickPixel(), -90); | |
| 271 | + $image->rotateImage($bg, -90); | |
| 246 | 272 | break; |
| 273 | + default: | |
| 274 | + $image->destroy(); | |
| 275 | + return $file; | |
| 247 | 276 | } |
| 248 | 277 | // Strip EXIF data to prevent further issues |
| 249 | 278 | $image->stripImage(); |
| 250 | 279 | // Save the rotated image |
| @@ -250,9 +279,9 @@ | ||
| 250 | 279 | // Save the rotated image |
| 251 | 280 | $image->writeImage($file['file']); |
| 252 | 281 | $image->destroy(); |
| 253 | 282 | } catch (\Exception $e) { |
| 254 | - | |
| 283 | + // Leave the original file untouched if Imagick fails | |
| 255 | 284 | } |
| 256 | 285 | } elseif (function_exists('imagecreatefromjpeg')) { |
| 257 | 286 | // Use GD if Imagick is not available |
| 258 | 287 | $image = @imagecreatefromjpeg($file['file']); |
| @@ -259,18 +288,36 @@ | ||
| 259 | 288 | if ($image === false) { |
| 260 | 289 | return $file; |
| 261 | 290 | } |
| 262 | 291 | |
| 292 | + // GD's imagerotate uses counter-clockwise angles, so -90 == 90° clockwise | |
| 263 | 293 | switch ($orientation) { |
| 294 | + case 2: // mirror horizontal | |
| 295 | + imageflip($image, IMG_FLIP_HORIZONTAL); | |
| 296 | + break; | |
| 264 | 297 | case 3: // 180° |
| 265 | 298 | $image = imagerotate($image, 180, 0); |
| 266 | 299 | break; |
| 300 | + case 4: // mirror vertical | |
| 301 | + imageflip($image, IMG_FLIP_VERTICAL); | |
| 302 | + break; | |
| 303 | + case 5: // transpose (mirror vertical + 90° clockwise) | |
| 304 | + imageflip($image, IMG_FLIP_VERTICAL); | |
| 305 | + $image = imagerotate($image, -90, 0); | |
| 306 | + break; | |
| 267 | 307 | case 6: // 90° clockwise |
| 268 | 308 | $image = imagerotate($image, -90, 0); |
| 269 | 309 | break; |
| 310 | + case 7: // transverse (mirror horizontal + 90° clockwise) | |
| 311 | + imageflip($image, IMG_FLIP_HORIZONTAL); | |
| 312 | + $image = imagerotate($image, -90, 0); | |
| 313 | + break; | |
| 270 | 314 | case 8: // 90° counter-clockwise |
| 271 | 315 | $image = imagerotate($image, 90, 0); |
| 272 | 316 | break; |
| 317 | + default: | |
| 318 | + imagedestroy($image); | |
| 319 | + return $file; | |
| 273 | 320 | } |
| 274 | 321 | |
| 275 | 322 | // Save the rotated image |
| 276 | 323 | imagejpeg($image, $file['file'], 100); |