From 3d25ad7de4fdbb3eba2cde2a62422e6be5d79a0a Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Tue, 25 Aug 2026 22:57:22 +0000
Subject: [PATCH] =It's been a minute. I went through the Routes and associated Managers and ensured they played together well. Reworked the Cache.php, and I think I caught all the references. Moving away from JVBase() root class, to individuall classes that are Instanced. Double checked for the ABSPATH check in every file, and added index.php to every directory that didn't already have it. Also still working on the MenuBlock to work with WooCommerce for now for Northeh
---
inc/managers/UploadManager.php | 498 +++++++++++++++++++++++++++++++++++++-----------------
1 files changed, 340 insertions(+), 158 deletions(-)
diff --git a/inc/managers/UploadManager.php b/inc/managers/UploadManager.php
index d1cd220..4889dbc 100644
--- a/inc/managers/UploadManager.php
+++ b/inc/managers/UploadManager.php
@@ -1,9 +1,14 @@
<?php
namespace JVBase\managers;
-use JVBase\JVB;
+use JVBase\base\Site;
+use JVBase\Instance;
use Exception;
use Imagick;
+use JVBase\managers\queue\executors\UploadExecutor;
+use JVBase\managers\queue\mergers\UploadMerger;
+use JVBase\managers\queue\Queue;
+use JVBase\managers\queue\TypeConfig;
use WP_Error;
if (!defined('ABSPATH')) {
@@ -11,11 +16,32 @@
}
/**
- * Flexible file upload manager for images, videos, and documents
- * Supports configurable directory structures and processing options
+ * The goal here was mainly for membership sites, to organize files by userID, rather than the date structure.
+ * This way, if a user deletes their account, or performs a data request, we can simply copy their directory.
+ *
+ * I started with user name so we could search by name, but issues arose if a user changed their name/display name. So I set it to go to user_id.
+ *
+ * The general flow is:
+ * -> Upload, ensure files are stored in appropriate directory, usually {root}/tmp
+ * -> Conversion is queued with Queue, as with the /tmp cleanup
+ *
+ * Proposed directory structure:
+ * Site::has('membership') || Site::has('is_directory')
+ * -> defaults to {user_id}/{post_type}/file
+ * Default:
+ * -> defaults to {post_type}/file
+ * Drawback: if a post is uploaded to one post type, then used in another, the organization is slightly flawed.
+ *
+ * Also, we wanted to ensure images were converted to webp, for speed.
+ * -> The front-end javascript attempts to do this in browser
+ * -> If this couldn't be handled, it is queued for server processing
+ * Of course, some integrations (even google, sillies) only accept jpeg/png, so in some cases we need a jpeg fallback
+ *
+ *
*/
class UploadManager
{
+ use Instance;
protected array $allowedTypes = [
// Images
'image/jpeg' => 'image',
@@ -73,16 +99,179 @@
'original_retention' => 2592000, // 30 days
];
+ /******************************************************************
+ * UPLOAD SETTINGS
+ ******************************************************************/
+ /**
+ * @var array|int[] Max size of file types
+ */
+ protected array $maxSize = [
+ 'image' => 5242880, // 5MB
+ 'video' => 104857600, // 100MB
+ 'document' => 15728640 // 15MB
+ ];
+ //Image Specific
+ /**
+ * @var bool Whether to convert the image
+ */
+ protected bool $convertImage = true;
+ /**
+ * @var string Default image conversion
+ */
+ protected string $convertImageTo = 'webp';
+ /**
+ * @var int Default image quality
+ */
+ protected int $convertQuality = 80;
+ /**
+ * @var bool Whether to optimize images
+ */
+ protected bool $optimizeImages = true;
+ /**
+ * @var bool Whether to create image thumbnails
+ */
+ protected bool $createThumbnails = true;
+ //Video specific
+ /**
+ * @var bool Whether to automatically extract a thumbnail from a video
+ */
+ protected bool $extractVideoThumbnail = true;
+ /**
+ * @var int Time, in microseconds, to grab thumbnail from
+ */
+ protected int $videoThumbnailPosition = 0;
+ //Document specific
+ /**
+ * @var bool Whether to extract thumbnail from document.
+ */
+ protected bool $extractDocumentThumbnail = false;
+ /**
+ * @var int How long to keep originals (default 3 months)
+ */
+ protected int $keep_originals;
+ /******************************************************************
+ * UPLOAD DIRECTORIES
+ ******************************************************************/
+ /**
+ * @var string WordPress' base upload directory
+ */
protected string $upload_dir;
+ /**
+ * @var string WordPress' base upload directory url
+ */
protected string $upload_url;
- public function __construct()
+ protected string $dir_pattern;
+ /*****************************************************************
+ * FEATURE FLAG
+ *****************************************************************/
+ protected bool $has_imagick = false;
+ private function __construct()
{
$upload = wp_upload_dir();
$this->upload_dir = $upload['basedir'];
$this->upload_url = $upload['baseurl'];
- // Check for Imagick
- $this->defaultConfig['use_imagick'] = extension_loaded('imagick');
+ if (Site::has('membership') || Site::has('is_directory')) {
+ $this->dir_pattern = '{user_id}/{post_type}';
+ } else {
+ $this->dir_pattern = '{post_type}';
+ }
+ $this->has_imagick = extension_loaded('imagick');
+ $this->keep_originals = MONTH_IN_SECONDS * 3;
+
+ add_action('init', [$this, 'registerUploadExecutors'], 5);
+ }
+
+ /**
+ * Register upload operation types with the queue's TypeRegistry
+ */
+ public function registerUploadExecutors(): void
+ {
+ $registry = Queue::getInstance()->registry();
+ $executor = new UploadExecutor();
+ $merger = new UploadMerger('secured_files');
+
+ // Image uploads - chunked at 5 files
+ $registry->register('image_upload', new TypeConfig(
+ mergeable: $merger,
+ executor: $executor,
+ chunkKey: 'secured_files',
+ chunkSize: 3
+ ));
+
+ // Video uploads - one at a time (heavy processing)
+ $registry->register('video_upload', new TypeConfig(
+ mergeable: $merger,
+ executor: $executor,
+ chunkKey: 'secured_files',
+ chunkSize: 1
+ ));
+
+ // Document uploads - chunked at 10
+ $registry->register('document_upload', new TypeConfig(
+ mergeable: $merger,
+ executor: $executor,
+ chunkKey: 'secured_files',
+ chunkSize: 5
+ ));
+
+ // Metadata updates
+ $registry->register('update_image_meta', new TypeConfig(
+ executor: $executor
+ ));
+
+ // Cleanup - chunked at 5
+ $registry->register('temporary_cleanup', new TypeConfig(
+ executor: $executor,
+ chunkKey: 'files',
+ chunkSize: 5
+ ));
+
+ // Attach to content (depends on upload completing)
+ $registry->register('attach_upload_to_content', new TypeConfig(
+ executor: $executor
+ ));
+
+ // Process upload groups into posts
+ $registry->register('process_upload_groups', new TypeConfig(
+ executor: $executor,
+ chunkKey: 'posts',
+ chunkSize: 5
+ ));
+ }
+
+ /**
+ * @param string|array $file_path
+ * @param array $context
+ * @return ?string
+ * @throws Exception
+ */
+ protected function testFile(string|array $file_path, array $context):?string
+ {
+ $file_type = null;
+ if (is_array($file_path)) {
+ if (!isset($file_path['tmp_name']) || $file_path['error'] !== UPLOAD_ERR_OK) {
+ throw new Exception('Invalid file upload');
+ }
+ $file_path = $file_path['tmp_name'];
+ }
+ // Validate file upload
+ if (!isset($file_path)) {
+ throw new Exception('Invalid file upload');
+ }
+
+ $mime_type = mime_content_type($file_path);
+ $file_type = $this->allowedTypes[$mime_type] ?? 'unknown';
+ if ($file_type === 'unknown') {
+ throw new Exception('Unsupported file type: ' . $mime_type);
+ }
+
+ // Check allowed types if specified
+ if (array_key_exists('allowed_types', $context) && !in_array($mime_type, $context['allowed_types'])) {
+ throw new Exception('File type not allowed: ' . $mime_type);
+ }
+
+ return $file_type;
}
/**
@@ -94,26 +283,10 @@
public function secureUploadedFile(array $file_data, array $context): array
{
try {
- // Validate file upload
- if (!isset($file_data['tmp_name']) || $file_data['error'] !== UPLOAD_ERR_OK) {
- throw new Exception('Invalid file upload');
- }
+ $file_type = $this->testFile($file_data, $context);
- $mime_type = mime_content_type($file_data['tmp_name']);
- $file_type = $this->allowedTypes[$mime_type] ?? 'unknown';
- if ($file_type === 'unknown') {
- throw new Exception('Unsupported file type: ' . $mime_type);
- }
-
- // Check allowed types if specified
- if ($this->defaultConfig['allowed_types'] && !in_array($mime_type, $this->defaultConfig['allowed_types'])) {
- throw new Exception('File type not allowed: ' . $mime_type);
- }
-
- $temp_dir = $this->generateDirectory($file_type, "{user_id}/temp", $context);
-
- // Ensure directories exist
- $this->ensureDirectories($temp_dir);
+ $context['pattern'] = $this->dir_pattern.'/tmp';
+ $temp_dir = $this->generateDirectory($file_type, $context);
// Generate a unique filename for temporary storage
$temp_filename = uniqid() . '_' . sanitize_file_name($file_data['name']);
@@ -129,15 +302,15 @@
// Return metadata about the stored file
return [
- 'temp_path' => $temp_path,
+ 'temp_path' => $temp_path,
'original_name' => $file_data['name'],
- 'mime_type' => $file_data['type'],
- 'file_type' => $file_type,
- 'file_size' => $file_data['size'],
- 'stored_at' => current_time('mysql')
+ 'mime_type' => $file_data['type'],
+ 'file_type' => $file_type,
+ 'file_size' => $file_data['size'],
+ 'stored_at' => current_time('mysql')
];
} catch (Exception $e) {
- JVB()->error()->log('Failed to store uploaded file: ' . print_r($e->getMessage(), true));
+ Errors::getInstance()->log('UploadManager','Failed to store uploaded file: ' . print_r($e->getMessage(), true));
return [];
}
}
@@ -152,60 +325,32 @@
public function processUpload(string $temp_path, array $context): array|WP_Error
{
try {
- // Validate temp file exists
- if (!file_exists($temp_path)) {
- throw new Exception('Temporary file not found: ' . $temp_path);
- }
-
- // Validate MIME type
- $mime_type = mime_content_type($temp_path);
- if (!$this->validateMimeType($temp_path, $mime_type)) {
- throw new Exception('Invalid or potentially dangerous file type');
- }
- $file_type = $this->allowedTypes[$mime_type] ?? 'unknown';
-
- if ($file_type === 'unknown') {
- throw new Exception('Unsupported file type: ' . $mime_type);
- }
-
- // Merge config
- $config = array_merge($this->defaultConfig, $context['config'] ?? [], $context);
+ $file_type = $this->testFile($temp_path, $context);
// Extract context
$user_id = $context['user_id'] ?? get_current_user_id();
$post_id = $context['post_id'] ?? 0;
- // Check allowed types if specified
- if (!empty($config['allowed_types']) && !in_array($mime_type, $config['allowed_types'])) {
- throw new Exception('File type not allowed: ' . $mime_type);
- }
-
// Validate file size
- $this->validateFileSize($temp_path, $file_type, $config);
+ $this->validateFileSize($temp_path, $file_type, $context);
// Generate directory structure for final storage
- $directory = $this->generateDirectory($file_type, $config['directory_pattern'] ?? '{user_id}/{content}/{file_type}', $context);
-
- // Ensure directories exist
- $this->ensureDirectories($directory);
+ $directory = $this->generateDirectory($file_type, $context);
// Generate filename
$original_name = $context['original_name'] ?? basename($temp_path);
$filename = $this->generateFilename($original_name, $context);
- // Store original from temp
- $original_path = $this->storeOriginalFromTemp($temp_path, $directory, $filename);
-
// Process based on file type
return match($file_type) {
- 'image' => $this->processImage($original_path, $directory, $filename, $post_id, $config, $context),
- 'video' => $this->processVideo($original_path, $directory, $filename, $post_id, $config, $context),
- 'document' => $this->processDocument($original_path, $directory, $filename, $post_id, $config, $context),
+ 'image' => $this->processImage($temp_path, $directory, $filename, $post_id, $context),
+ 'video' => $this->processVideo($temp_path, $directory, $filename, $post_id, $context),
+ 'document' => $this->processDocument($temp_path, $directory, $filename, $post_id, $context),
default => throw new Exception('Unknown file type')
};
} catch (Exception $e) {
- JVB()->error()->log(
+ Errors::getInstance()->log(
'[UploadManager]:processUpload',
$e->getMessage(),
['temp_path' => $temp_path, 'context' => $context]
@@ -215,21 +360,6 @@
}
}
- /**
- * Store original file from temp location (not from PHP upload)
- */
- protected function storeOriginalFromTemp(string $temp_path, string $directory, string $filename): string
- {
- $ext = pathinfo($temp_path, PATHINFO_EXTENSION);
- $original_path = "{$this->upload_dir}/{$directory}/originals/{$filename}.{$ext}";
-
- // Copy from temp to final location
- if (!copy($temp_path, $original_path)) {
- throw new Exception('Failed to store original file');
- }
-
- return $original_path;
- }
/**
* Clean up empty temporary directories
@@ -262,24 +392,52 @@
@rmdir($temp_base);
}
}
+
/**
* Generate directory structure based on pattern
+ * @param string $file_type
+ * @param array $config
+ * @return string
+ * @throws Exception
*/
- protected function generateDirectory(string $file_type, string $pattern, array $context): string
+ public function generateDirectory(string $file_type, array $config): string
{
- $replacements = [
- '{user_id}' => $context['user_id'] ?? get_current_user_id(),
- '{post_type}' => $context['content'] ?? '',
- '{content}' => $context['content'] ?? '',
- '{file_type}' => $file_type,
- '{year}' => date('Y'),
- '{month}' => date('m'),
- ];
+ $pattern = array_key_exists('pattern', $config) && is_string($config['pattern']) ? $config['pattern'] : $this->dir_pattern;
- $directory = str_replace(array_keys($replacements), array_values($replacements), $pattern);
+ $pattern = explode('/', $pattern);
+ $parts = [];
+ foreach ($pattern as $part) {
+ $newPart = match($part) {
+ '{user_id}' => $context['user_id'] ?? null,
+ '{post_type}', '{content}' => $context['content'] ?? null,
+ '{tax}', '{taxonomy}' => $context['taxonomy'] ?? null,
+ '{term}' => $context['term'] ?? null,
+ '{file_type}' => $file_type,
+ '{year}' => date('Y'),
+ '{month}' => date('m'),
+ '{day}' => date('d'),
+ default => $part
+ };
+ if (is_null($newPart)) {
+ error_log('[Uploader] Pattern key was not provided for '.$part);
+ }
+ if (str_contains($newPart, '{')) {
+ error_log('[Uploader] Unhandled pattern found: '. $newPart);
+ }
+ $newPart = $this->sanitizeFileName($newPart);
+ $parts[] = $newPart;
+ }
+ //Remove any null values
+ $parts = array_filter($parts);
+
+ $directory = implode('/', $parts);
// Allow filtering
- return apply_filters('jvb_upload_directory', $directory, $file_type, $context);
+ $directory = apply_filters('jvb_upload_directory', $directory, $file_type, $config);
+
+ // Ensure directories exist
+ $this->ensureDirectories($directory);
+ return $directory;
}
/**
@@ -288,8 +446,7 @@
protected function ensureDirectories(string $rel_path): void
{
$dirs = [
- "{$this->upload_dir}/{$rel_path}",
- "{$this->upload_dir}/{$rel_path}/originals"
+ "{$this->upload_dir}/{$rel_path}"
];
foreach ($dirs as $dir) {
@@ -299,28 +456,26 @@
}
}
- /**
- * Store original file
- */
- protected function storeOriginal(string $tmp_file, string $directory, string $filename): string
- {
- $ext = pathinfo($tmp_file, PATHINFO_EXTENSION);
- $original_path = "{$this->upload_dir}/{$directory}/originals/{$filename}.{$ext}";
-
- if (!move_uploaded_file($tmp_file, $original_path)) {
- throw new Exception('Failed to store original file');
- }
-
- return $original_path;
- }
/**
* Validate file size based on type and config
+ * @param string $file_path
+ * @param string $file_type
+ * @param array $config
+ * @return void
+ * @throws Exception
*/
protected function validateFileSize(string $file_path, string $file_type, array $config): void
{
$size = filesize($file_path);
- $max_size = $config['max_size'][$file_type] ?? $this->defaultConfig['max_size'][$file_type];
+ $max_size = $this->maxSize[$file_type];
+ if (array_key_exists('max_size', $config)) {
+ if (is_int($config['max_size'])) {
+ $max_size = $config['max_size'];
+ } else if (is_array($config['max_size']) && array_key_exists($file_type, $config['max_size'])) {
+ $max_size = $config['max_size'][$file_type];
+ }
+ }
if ($size > $max_size) {
$max_mb = round($max_size / 1048576, 2);
@@ -354,7 +509,7 @@
* Process image file
* @throws Exception
*/
- protected function processImage(string $original_path, string $directory, string $filename, int $post_id, array $config, array $context): array
+ protected function processImage(string $original_path, string $directory, string $filename, int $post_id, array $context): array
{
$full_dir = "{$this->upload_dir}/{$directory}";
$original_mime = mime_content_type($original_path);
@@ -363,17 +518,18 @@
$should_convert = false;
$target_format = false;
- if ($config['convert'] && $config['convert'] !== false) {
- $target_format = strtolower($config['convert']);
-
- // Validate format
- if (!isset($this->supportedFormats[$target_format])) {
- throw new Exception("Unsupported conversion format: {$target_format}");
+ if ((array_key_exists('convert', $context) && $context['convert'] !== false) || $this->convertImage) {
+ $target_format = empty($context['convertTo']??'') ? $this->convertImage : $context['convertTo'];
+ if (!empty($target_format)) {
+ // Validate format
+ if (!isset($this->supportedFormats[$target_format])) {
+ error_log('[Uploader] Unsupported conversion format: '.$target_format.'... will not convert');
+ } else {
+ // Check if conversion is needed
+ $target_mime = $this->supportedFormats[$target_format];
+ $should_convert = ($original_mime !== $target_mime);
+ }
}
-
- // Check if conversion is needed
- $target_mime = $this->supportedFormats[$target_format];
- $should_convert = ($original_mime !== $target_mime);
}
// Convert or copy based on configuration
@@ -381,15 +537,18 @@
$final_path = "{$full_dir}/{$filename}.{$target_format}";
try {
+
$this->convertImage(
$original_path,
$final_path,
$target_format,
- $config['quality'],
- $config['use_imagick']
+ array_key_exists('quality', $context) && is_int($context['quality']) && $context['quality'] <= 100 ?
+ $context['quality'] :
+ $this->convertQuality,
);
+
} catch (Exception $e) {
- JVB()->error()->log('Image conversion failed: ' . print_r($e->getMessage(), true));
+ Errors::getInstance()->log('Uploader', 'Image conversion failed: ' . print_r($e->getMessage(), true));
// Fallback to original
$ext = pathinfo($original_path, PATHINFO_EXTENSION);
$final_path = "{$full_dir}/{$filename}.{$ext}";
@@ -412,17 +571,19 @@
}
// Generate thumbnails
- if ($config['create_thumbnails']) {
+ $hasOption = array_key_exists('create_thumbnails', $context);
+ if (($hasOption && $context['create_thumbnails']) || (!$hasOption && $this->createThumbnails)) {
$this->generateThumbnails($attachment_id);
}
return [
- 'success' => true,
+ 'success' => true,
'attachment_id' => $attachment_id,
- 'url' => wp_get_attachment_url($attachment_id),
- 'file' => $final_path,
- 'type' => 'image',
- 'format' => $target_format ?: pathinfo($final_path, PATHINFO_EXTENSION)
+ 'url' => wp_get_attachment_url($attachment_id),
+ 'file' => $final_path,
+ 'type' => 'image',
+ 'format' => $target_format ?: pathinfo($final_path, PATHINFO_EXTENSION),
+ 'context' => $context
];
}
@@ -430,7 +591,7 @@
* Process video file
* @throws Exception
*/
- protected function processVideo(string $original_path, string $directory, string $filename, int $post_id, array $config, array $context): array
+ protected function processVideo(string $original_path, string $directory, string $filename, int $post_id, array $context): array
{
$full_dir = "{$this->upload_dir}/{$directory}";
$ext = pathinfo($original_path, PATHINFO_EXTENSION);
@@ -443,29 +604,32 @@
try {
$attachment_id = $this->createAttachment($final_path, $filename, $context, $post_id);
} catch (Exception $e) {
- JVB()->error()->log('Attachment creation failed: '.print_r($e->getMessage(), true));
+ Errors::getInstance()->log('Uploader', 'Attachment creation failed: '.print_r($e->getMessage(), true));
return ['success' => false];
}
// Extract thumbnail if enabled
- if ($config['extract_video_thumbnail']) {
- $this->extractVideoThumbnail($attachment_id, $final_path, $config['video_thumbnail_time']);
+ $hasOption = array_key_exists('extract_thumbnail', $context);
+ if (($hasOption && $context['extract_thumbnail']) || (!$hasOption && $this->extractVideoThumbnail)) {
+ $time = $context['thumbnail_time']??$this->videoThumbnailPosition;
+ $this->extractVideoThumbnail($attachment_id, $final_path, $time);
}
return [
- 'success' => true,
+ 'success' => true,
'attachment_id' => $attachment_id,
- 'url' => wp_get_attachment_url($attachment_id),
- 'file' => $final_path,
- 'type' => 'video'
+ 'url' => wp_get_attachment_url($attachment_id),
+ 'file' => $final_path,
+ 'type' => 'video',
+ 'context' => $context
];
}
/**
* Process document file
*/
- protected function processDocument(string $original_path, string $directory, string $filename, int $post_id, array $config, array $context): array
+ protected function processDocument(string $original_path, string $directory, string $filename, int $post_id, array $context): array
{
$full_dir = "{$this->upload_dir}/{$directory}";
$ext = pathinfo($original_path, PATHINFO_EXTENSION);
@@ -478,36 +642,36 @@
try {
$attachment_id = $this->createAttachment($final_path, $filename, $context, $post_id);
} catch (Exception $e) {
- JVB()->error()->log('Conversion failed: '.print_r($e->getMessage(), true));
+ Errors::getInstance()->log('Uploader','Conversion failed: '.print_r($e->getMessage(), true));
return ['success' => false];
}
-
return [
- 'success' => true,
+ 'success' => true,
'attachment_id' => $attachment_id,
- 'url' => wp_get_attachment_url($attachment_id),
- 'file' => $final_path,
- 'type' => 'document'
+ 'url' => wp_get_attachment_url($attachment_id),
+ 'file' => $final_path,
+ 'type' => 'document',
+ 'context' => $context
];
}
/**
* Generate SEO-friendly filename
*/
- protected function generateFilename(string $original_name, array $context): string
+ public function generateFilename(string $original_name, array $context): string
{
$name_parts = pathinfo($original_name);
- $base_name = sanitize_title($name_parts['filename']);
+ $base_name = $this->sanitizeFileName($name_parts['filename']);
$user_data = array_key_exists('user_id', $context) ? get_userdata((int)$context['user_id']) : get_current_user();
$username = $user_data ? sanitize_title($user_data->display_name) : 'user';
$timestamp = time();
- return apply_filters(
+ return $this->sanitizeFileName(apply_filters(
'jvb_upload_filename',
- "{$username}-{$base_name}-{$timestamp}",
+ "{$base_name}-{$timestamp}",
$context
- );
+ ));
}
protected function sanitizeFileName(string $filename): string
@@ -570,7 +734,7 @@
* @param bool $replace Replace original file (default: true)
* @return array|WP_Error Result with new attachment details
*/
- public function convertImageTo(int $attachment_id, string $format, int $quality = 80, bool $replace = true): array|WP_Error
+ public function convertImageTo(int $attachment_id, string $format, int $quality = 80, bool $replace = false): array|WP_Error
{
try {
// Validate format
@@ -608,8 +772,7 @@
$new_path = $path_info['dirname'] . '/' . $new_filename;
// Perform conversion
- $use_imagick = $this->defaultConfig['use_imagick'];
- $this->convertImage($original_path, $new_path, $format, $quality, $use_imagick);
+ $this->convertImage($original_path, $new_path, $format, $quality);
if ($replace) {
// Replace the original file
@@ -645,16 +808,31 @@
/**
* Generic image conversion method
*/
- protected function convertImage(string $source, string $destination, string $format, int $quality, bool $use_imagick): void
+ /**
+ * @param string $source
+ * @param string $destination
+ * @param string $format
+ * @param int $quality
+ * @return void
+ * @throws Exception
+ */
+ protected function convertImage(string $source, string $destination, string $format, int $quality): void
{
- if ($use_imagick) {
+ if ($this->has_imagick) {
$this->convertWithImagick($source, $destination, $format, $quality);
} else {
$this->convertWithGd($source, $destination, $format, $quality);
}
}
+
/**
- * Convert image with Imagick (supports multiple formats)
+ * Convert image with Imagick
+ * @param string $source
+ * @param string $destination
+ * @param string $format
+ * @param int $quality
+ * @return void
+ * @throws Exception
*/
protected function convertWithImagick(string $source, string $destination, string $format, int $quality): void
{
@@ -678,14 +856,19 @@
$image->writeImage($destination);
$image->clear();
- $image->destroy();
} catch (Exception $e) {
throw new Exception("Imagick conversion to {$format} failed: " . $e->getMessage());
}
}
/**
- * Convert image with GD (supports multiple formats)
+ * Convert image with GD
+ * @param string $source
+ * @param string $destination
+ * @param string $format
+ * @param int $quality
+ * @return void
+ * @throws Exception
*/
protected function convertWithGd(string $source, string $destination, string $format, int $quality): void
{
@@ -750,5 +933,4 @@
// Placeholder for future implementation
apply_filters('jvb_extract_video_thumbnail', null, $attachment_id, $video_path, $time);
}
-
}
--
Gitblit v1.10.0