- Updated API calls in equipment.php, equipment_manage.php, and equipments_mass_update.php to use v2 endpoints. - Changed payload decoding from decode_payload to json_decode for consistency. - Enhanced invoice generation in factuur.php and webhook files to use a new email template and PDF structure. - Added new email and PDF templates for invoices to improve formatting and readability. - Improved marketing folder handling in marketing.php with better payload management. - Updated CSS for marketing to enhance UI interactions. - Added JavaScript checks for browser compatibility in softwaretool.php. - Adjusted user permissions in settingsprofiles.php to reflect new features.
336 lines
11 KiB
PHP
336 lines
11 KiB
PHP
<?php
|
|
defined($security_key) or exit;
|
|
|
|
//------------------------------------------
|
|
// Marketing Upload
|
|
//------------------------------------------
|
|
//Connect to DB
|
|
$pdo = dbConnect($dbname);
|
|
|
|
//SoldTo is empty
|
|
if (empty($partner->soldto) || $partner->soldto == ''){$soldto_search = '%';} else {$soldto_search = '-%';}
|
|
|
|
//default whereclause
|
|
list($whereclause,$condition) = getWhereclauselvl2("",$permission,$partner,'');
|
|
|
|
//BUILD UP PARTNERHIERARCHY FROM USER
|
|
$partner_hierarchy = $condition;
|
|
|
|
//QUERY AND VERIFY ALLOWED
|
|
if (isAllowed('marketing',$profile,$permission,'C') === 1){
|
|
if (!isset($_FILES['file'])) {
|
|
echo json_encode(['success' => false, 'error' => 'No file uploaded']);
|
|
exit;
|
|
}
|
|
|
|
$file = $_FILES['file'];
|
|
$folder_id = $_POST['folder_id'] ?? '';
|
|
$tags = isset($_POST['tags']) ? json_decode($_POST['tags'], true) : [];
|
|
$title = $_POST['title'] ?? pathinfo($file['name'], PATHINFO_FILENAME);
|
|
|
|
// Validate file type
|
|
$allowedTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'mp4', 'mov', 'avi'];
|
|
$filename = $file['name'];
|
|
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
|
|
|
if (!in_array($ext, $allowedTypes)) {
|
|
echo json_encode(['success' => false, 'error' => 'Invalid file type. Allowed: ' . implode(', ', $allowedTypes)]);
|
|
exit;
|
|
}
|
|
|
|
$imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
|
$isImage = in_array($ext, $imageTypes);
|
|
|
|
// For images over 10MB, automatically compress
|
|
if ($isImage && $file['size'] > 10000000) {
|
|
$compressed = compressImage($file['tmp_name'], $ext, 10000000);
|
|
if ($compressed === false) {
|
|
echo json_encode(['success' => false, 'error' => 'Failed to compress large image. Please reduce file size manually.']);
|
|
exit;
|
|
}
|
|
// Update file size after compression
|
|
$file['size'] = filesize($file['tmp_name']);
|
|
}
|
|
|
|
// Non-images must be under 10MB
|
|
if (!$isImage && $file['size'] > 25000000) {
|
|
echo json_encode(['success' => false, 'error' => 'File too large. Maximum size is 25MB.']);
|
|
exit;
|
|
}
|
|
|
|
// Create unique filename
|
|
$unique_filename = uniqid() . '_' . time() . '.' . $ext;
|
|
$target_dir = dirname(__FILE__, 4) . "/marketing/uploads/";
|
|
$target_file = $target_dir . $unique_filename;
|
|
$logical_path = "marketing/uploads/" . $unique_filename;
|
|
|
|
// Ensure upload directory exists
|
|
if (!file_exists($target_dir)) {
|
|
mkdir($target_dir, 0755, true);
|
|
}
|
|
|
|
if (move_uploaded_file($file['tmp_name'], $target_file)) {
|
|
// Generate thumbnail
|
|
$thumbnail_path = null;
|
|
$thumb_dir = $target_dir . "thumbs/";
|
|
if (!file_exists($thumb_dir)) {
|
|
mkdir($thumb_dir, 0755, true);
|
|
}
|
|
|
|
// Generate thumbnail for images
|
|
if (in_array($ext, ['jpg', 'jpeg', 'png', 'gif', 'webp'])) {
|
|
$thumbnail_file = $thumb_dir . $unique_filename;
|
|
if (generateThumbnail($target_file, $thumbnail_file, 200, 200)) {
|
|
$thumbnail_path = "marketing/uploads/thumbs/" . $unique_filename;
|
|
}
|
|
}
|
|
// Generate thumbnail for videos
|
|
elseif (in_array($ext, ['mp4', 'mov', 'avi'])) {
|
|
$thumbnail_filename = pathinfo($unique_filename, PATHINFO_FILENAME) . '.jpg';
|
|
$thumbnail_file = $thumb_dir . $thumbnail_filename;
|
|
if (generateVideoThumbnail($target_file, $thumbnail_file)) {
|
|
$thumbnail_path = "marketing/uploads/thumbs/" . $thumbnail_filename;
|
|
}
|
|
}
|
|
|
|
// Insert into database
|
|
$insert_sql = 'INSERT INTO `marketing_files` (`title`, `original_filename`, `file_path`, `thumbnail_path`, `file_type`, `file_size`, `folder_id`, `tags`, `createdby`, `accounthierarchy`) VALUES (?,?,?,?,?,?,?,?,?,?)';
|
|
$stmt = $pdo->prepare($insert_sql);
|
|
$stmt->execute([
|
|
$title,
|
|
$filename,
|
|
$logical_path,
|
|
$thumbnail_path,
|
|
$ext,
|
|
$file['size'],
|
|
$folder_id,
|
|
json_encode($tags),
|
|
$username,
|
|
$partner_hierarchy
|
|
]);
|
|
|
|
$file_id = $pdo->lastInsertId();
|
|
|
|
// Insert tags into separate table
|
|
if (!empty($tags)) {
|
|
$tag_sql = 'INSERT IGNORE INTO `marketing_tags` (`tag_name`) VALUES (?)';
|
|
$tag_stmt = $pdo->prepare($tag_sql);
|
|
|
|
$file_tag_sql = 'INSERT INTO `marketing_file_tags` (`file_id`, `tag_id`) SELECT ?, id FROM marketing_tags WHERE tag_name = ?';
|
|
$file_tag_stmt = $pdo->prepare($file_tag_sql);
|
|
|
|
foreach ($tags as $tag) {
|
|
$tag_stmt->execute([trim($tag)]);
|
|
$file_tag_stmt->execute([$file_id, trim($tag)]);
|
|
}
|
|
}
|
|
|
|
echo json_encode([
|
|
'success' => true,
|
|
'file_id' => $file_id,
|
|
'path' => $logical_path,
|
|
'thumbnail' => $thumbnail_path,
|
|
'message' => 'File uploaded successfully'
|
|
]);
|
|
|
|
} else {
|
|
echo json_encode(['success' => false, 'error' => 'Failed to move uploaded file']);
|
|
}
|
|
} else {
|
|
echo json_encode(['success' => false, 'error' => 'Insufficient permissions']);
|
|
}
|
|
|
|
// Function to compress large images
|
|
function compressImage($source, $ext, $maxSize) {
|
|
$info = @getimagesize($source);
|
|
if ($info === false) return false;
|
|
|
|
$mime = $info['mime'];
|
|
|
|
// Load image
|
|
switch ($mime) {
|
|
case 'image/jpeg':
|
|
$image = @imagecreatefromjpeg($source);
|
|
break;
|
|
case 'image/png':
|
|
$image = @imagecreatefrompng($source);
|
|
break;
|
|
case 'image/gif':
|
|
$image = @imagecreatefromgif($source);
|
|
break;
|
|
case 'image/webp':
|
|
$image = @imagecreatefromwebp($source);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
if ($image === false) return false;
|
|
|
|
$width = imagesx($image);
|
|
$height = imagesy($image);
|
|
|
|
// Start with 90% quality and reduce dimensions if needed
|
|
$quality = 90;
|
|
$scale = 1.0;
|
|
$tempFile = $source . '.tmp';
|
|
|
|
// Try progressive compression
|
|
while (true) {
|
|
// Calculate new dimensions
|
|
$newWidth = (int)($width * $scale);
|
|
$newHeight = (int)($height * $scale);
|
|
|
|
// Create resized image
|
|
$resized = imagecreatetruecolor($newWidth, $newHeight);
|
|
|
|
// Preserve transparency for PNG/GIF
|
|
if ($mime === 'image/png' || $mime === 'image/gif') {
|
|
imagealphablending($resized, false);
|
|
imagesavealpha($resized, true);
|
|
$transparent = imagecolorallocatealpha($resized, 255, 255, 255, 127);
|
|
imagefilledrectangle($resized, 0, 0, $newWidth, $newHeight, $transparent);
|
|
}
|
|
|
|
imagecopyresampled($resized, $image, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
|
|
|
|
// Save with current quality
|
|
if ($ext === 'jpg' || $ext === 'jpeg') {
|
|
imagejpeg($resized, $tempFile, $quality);
|
|
} elseif ($ext === 'png') {
|
|
// PNG compression level (0-9, where 9 is best compression)
|
|
$pngQuality = (int)((100 - $quality) / 11);
|
|
imagepng($resized, $tempFile, $pngQuality);
|
|
} elseif ($ext === 'webp') {
|
|
imagewebp($resized, $tempFile, $quality);
|
|
} else {
|
|
imagegif($resized, $tempFile);
|
|
}
|
|
|
|
imagedestroy($resized);
|
|
|
|
$fileSize = filesize($tempFile);
|
|
|
|
// If file is small enough, use it
|
|
if ($fileSize <= $maxSize) {
|
|
imagedestroy($image);
|
|
rename($tempFile, $source);
|
|
return true;
|
|
}
|
|
|
|
// If we've reduced too much, give up
|
|
if ($quality < 50 && $scale < 0.5) {
|
|
imagedestroy($image);
|
|
@unlink($tempFile);
|
|
return false;
|
|
}
|
|
|
|
// Reduce quality or scale
|
|
if ($quality > 50) {
|
|
$quality -= 10;
|
|
} else {
|
|
$scale -= 0.1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Function to generate thumbnail
|
|
function generateThumbnail($source, $destination, $width, $height) {
|
|
$info = getimagesize($source);
|
|
if ($info === false) return false;
|
|
|
|
$mime = $info['mime'];
|
|
|
|
switch ($mime) {
|
|
case 'image/jpeg':
|
|
$image = imagecreatefromjpeg($source);
|
|
break;
|
|
case 'image/png':
|
|
$image = imagecreatefrompng($source);
|
|
break;
|
|
case 'image/gif':
|
|
$image = imagecreatefromgif($source);
|
|
break;
|
|
case 'image/webp':
|
|
$image = imagecreatefromwebp($source);
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
if ($image === false) return false;
|
|
|
|
$original_width = imagesx($image);
|
|
$original_height = imagesy($image);
|
|
|
|
// Calculate aspect ratio
|
|
$aspect_ratio = $original_width / $original_height;
|
|
|
|
if ($width / $height > $aspect_ratio) {
|
|
$new_width = $height * $aspect_ratio;
|
|
$new_height = $height;
|
|
} else {
|
|
$new_height = $width / $aspect_ratio;
|
|
$new_width = $width;
|
|
}
|
|
|
|
$thumbnail = imagecreatetruecolor($new_width, $new_height);
|
|
|
|
// Preserve transparency
|
|
imagealphablending($thumbnail, false);
|
|
imagesavealpha($thumbnail, true);
|
|
$transparent = imagecolorallocatealpha($thumbnail, 255, 255, 255, 127);
|
|
imagefilledrectangle($thumbnail, 0, 0, $new_width, $new_height, $transparent);
|
|
|
|
imagecopyresampled($thumbnail, $image, 0, 0, 0, 0, $new_width, $new_height, $original_width, $original_height);
|
|
|
|
// Save thumbnail
|
|
switch ($mime) {
|
|
case 'image/jpeg':
|
|
$result = imagejpeg($thumbnail, $destination, 85);
|
|
break;
|
|
case 'image/png':
|
|
$result = imagepng($thumbnail, $destination, 8);
|
|
break;
|
|
case 'image/gif':
|
|
$result = imagegif($thumbnail, $destination);
|
|
break;
|
|
case 'image/webp':
|
|
$result = imagewebp($thumbnail, $destination, 85);
|
|
break;
|
|
default:
|
|
$result = false;
|
|
}
|
|
|
|
imagedestroy($image);
|
|
imagedestroy($thumbnail);
|
|
|
|
return $result;
|
|
}
|
|
|
|
// Function to generate video thumbnail
|
|
function generateVideoThumbnail($source, $destination) {
|
|
// Check if ffmpeg is available
|
|
$ffmpeg = trim(shell_exec('which ffmpeg 2>/dev/null'));
|
|
if (empty($ffmpeg)) {
|
|
return false;
|
|
}
|
|
|
|
// Generate thumbnail from video at 1 second mark
|
|
// -i: input file
|
|
// -ss: seek to 1 second
|
|
// -vframes 1: extract one frame
|
|
// -vf: scale to 200x200 maintaining aspect ratio
|
|
$command = sprintf(
|
|
'%s -i %s -ss 00:00:01 -vframes 1 -vf "scale=200:200:force_original_aspect_ratio=decrease" %s 2>&1',
|
|
escapeshellarg($ffmpeg),
|
|
escapeshellarg($source),
|
|
escapeshellarg($destination)
|
|
);
|
|
|
|
exec($command, $output, $return_code);
|
|
|
|
return $return_code === 0 && file_exists($destination);
|
|
}
|
|
|
|
?>
|