You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
276 lines
8.9 KiB
276 lines
8.9 KiB
<?php
|
|
$min_pixels_before_compression = 999;
|
|
|
|
function generate_unique_filename(string $prefix = ''): string {
|
|
$timestamp = microtime(true); // Current timestamp with microseconds
|
|
$random = mt_rand(); // Random number (better than rand() for uniqueness)
|
|
$hash = md5($timestamp . $random); // MD5 hash of timestamp and random number
|
|
|
|
// Combine prefix (if provided) with the hash
|
|
$filename = $prefix . $hash;
|
|
|
|
return $filename;
|
|
}
|
|
|
|
/**
|
|
* Make sure uploads (LIKE Images, etc...) do NOT run PHP code!!
|
|
* Checks for PHP tags inside of file.
|
|
* @param string $file
|
|
* @return bool true if PHP was found
|
|
*/
|
|
function file_contains_php(string $file): bool {
|
|
$file_handle = fopen($file, "r");
|
|
while (!feof($file_handle)) {
|
|
$line = fgets($file_handle);
|
|
$pos = strpos($line, '<?php');
|
|
if ($pos !== false) {
|
|
fclose($file_handle);
|
|
return true;
|
|
}
|
|
}
|
|
fclose($file_handle);
|
|
return false;
|
|
}
|
|
|
|
function rename_upload(string $uploadName, string $fileName, false|string $rndFile): false|string {
|
|
if (file_contains_php($uploadName)) {
|
|
@unlink($uploadName); // stop attacks by a Delete of the PHP Image file!!
|
|
return false;
|
|
}
|
|
if ($rndFile === false) {
|
|
return false;
|
|
}
|
|
|
|
list($originalWidth, $originalHeight, $imageType) = getimagesize($uploadName);
|
|
if ($originalWidth == 0 || $originalHeight == 0) {
|
|
return false;
|
|
}
|
|
|
|
// File Name without EXT type or Path
|
|
$fileNameWithoutExt = pathinfo($uploadName, PATHINFO_FILENAME);
|
|
|
|
$type = match($imageType) {
|
|
IMAGETYPE_JPEG => '.jpg',
|
|
IMAGETYPE_PNG => '.png',
|
|
IMAGETYPE_GIF => '.gif',
|
|
default => false,
|
|
};
|
|
if ($type === false) {
|
|
return false;
|
|
}
|
|
|
|
$success = rename($uploadName, $GLOBALS['uploadDir'] . 'orignal_' . $rndFile . '_' . $fileNameWithoutExt . $type);
|
|
return ($success) ? 'orignal_' . $rndFile . '_' . $fileNameWithoutExt . $type : false;
|
|
}
|
|
|
|
function get_size(int $target, int $original): int {
|
|
$min_pixels_before_compression = $GLOBALS['min_pixels_before_compression'];
|
|
if ($target == 0) {
|
|
return ($original > $min_pixels_before_compression) ? $original / 2 : $original;
|
|
}
|
|
if ($target < $original) {
|
|
return $target;
|
|
}
|
|
return $original;
|
|
}
|
|
|
|
function image_compression(string $uploadName, string $fileName, array $images): array {
|
|
$rnd_name = generate_unique_filename();
|
|
if (!count($images)) {
|
|
return [];
|
|
}
|
|
$a_of_images = [];
|
|
foreach($images as $image) {
|
|
$name = $image['name'] ?? false;
|
|
$width = $image['width'] ?? false;
|
|
$height = $image['height'] ?? false;
|
|
$crop = $image['crop'] ?? false;
|
|
if ($name === false || $width === false || $height === false) {
|
|
continue;
|
|
}
|
|
$name .= '_' . $rnd_name;
|
|
if ($crop) {
|
|
$file = do_image_crop($uploadName, $fileName, $name, $width, $height, $rnd_name);
|
|
} else {
|
|
$file = do_image_compression($uploadName, $fileName, $name, $width, $height);
|
|
}
|
|
if ($file === false) {
|
|
continue;
|
|
}
|
|
$a_of_images[] = $file;
|
|
}
|
|
$org_file = rename_upload($uploadName, $fileName, $rnd_name);
|
|
if ($org_file !== false) {
|
|
$a_of_images[] = $org_file;
|
|
}
|
|
return $a_of_images;
|
|
}
|
|
|
|
function do_image_compression(string $uploadName, string $fileName, string $newName, int $targetWidth, int $targetHeight): false|string {
|
|
|
|
list($originalWidth, $originalHeight, $imageType) = getimagesize($uploadName);
|
|
if ($originalWidth == 0 || $originalHeight == 0) {
|
|
return $GLOBALS['image_error'];
|
|
}
|
|
|
|
// File Name without EXT type or Path
|
|
$fileNameWithoutExt = pathinfo($fileName, PATHINFO_FILENAME);
|
|
|
|
switch ($imageType) {
|
|
case IMAGETYPE_JPEG:
|
|
$img = imagecreatefromjpeg($uploadName);
|
|
$type = '.jpg';
|
|
break;
|
|
case IMAGETYPE_PNG:
|
|
$img = imagecreatefrompng($uploadName);
|
|
$type = '.png';
|
|
break;
|
|
case IMAGETYPE_GIF:
|
|
$img = imagecreatefromgif($uploadName);
|
|
$type = '.gif';
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
if ($img === false) {
|
|
return false;
|
|
}
|
|
|
|
$scaledFileName = $GLOBALS['uploadDir'] . $newName . '_' . $fileNameWithoutExt . $type;
|
|
|
|
// Calculate half image sizes for scaling
|
|
$newWidth = get_size($targetWidth, $originalWidth);
|
|
$newHeight = get_size($targetHeight, $originalHeight);
|
|
|
|
// Create a new true color image
|
|
$scaledImage = imagecreatetruecolor($newWidth, $newHeight);
|
|
// Enable transparency
|
|
imagealphablending($scaledImage, false);
|
|
imagesavealpha($scaledImage, true);
|
|
|
|
// Copy and resize the original image into the new image
|
|
imagecopyresampled(
|
|
$scaledImage, $img,
|
|
0, 0, 0, 0,
|
|
$newWidth, $newHeight,
|
|
$originalWidth, $originalHeight
|
|
);
|
|
|
|
switch ($imageType) {
|
|
case IMAGETYPE_JPEG:
|
|
$quality = $GLOBALS['JPEG_quality'];
|
|
imagejpeg($scaledImage, $scaledFileName, $quality);
|
|
break;
|
|
case IMAGETYPE_PNG:
|
|
$compression =$GLOBALS['PNG_compression'];
|
|
$transparentColor = imagecolorallocatealpha($scaledImage, 0, 0, 0, 127);
|
|
imagefill($scaledImage, 0, 0, $transparentColor);
|
|
imagepng($scaledImage, $scaledFileName, $compression);
|
|
break;
|
|
case IMAGETYPE_GIF:
|
|
$number_of_colors = $GLOBALS['GIF_number_of_colors'];
|
|
// Reduce the number of colors to make the file smaller
|
|
imagetruecolortopalette($scaledImage, false, $number_of_colors);
|
|
imagegif($scaledImage, $scaledFileName);
|
|
break;
|
|
}
|
|
|
|
// Free up memory
|
|
imagedestroy($img);
|
|
imagedestroy($scaledImage);
|
|
|
|
return $newName . '_' . $fileNameWithoutExt . $type;
|
|
}
|
|
|
|
function do_image_crop(string $uploadName, string $fileName, string $newName, int $targetWidth, int $targetHeight, string $rnd_name): false|string {
|
|
|
|
if (! file_exists($GLOBALS['uploadDir'] . 'half_' . $rnd_name . '_' . $fileName)) {
|
|
$scaledFileName = $GLOBALS['uploadDir'] . do_image_compression($uploadName, $fileName, "half_" . $rnd_name, $targetWidth, $targetHeight);
|
|
} else {
|
|
$scaledFileName = $GLOBALS['uploadDir'] . 'half_' . $rnd_name . '_' . $fileName;
|
|
}
|
|
list($originalWidth, $originalHeight, $imageType) = getimagesize($scaledFileName);
|
|
|
|
// File Name without EXT type or Path
|
|
$fileNameWithoutExt = pathinfo($fileName, PATHINFO_FILENAME);
|
|
|
|
switch ($imageType) {
|
|
case IMAGETYPE_JPEG:
|
|
$img = imagecreatefromjpeg($scaledFileName);
|
|
$type = '.jpg';
|
|
break;
|
|
case IMAGETYPE_PNG:
|
|
$img = imagecreatefrompng($scaledFileName);
|
|
$type = '.png';
|
|
break;
|
|
case IMAGETYPE_GIF:
|
|
$img = imagecreatefromgif($scaledFileName);
|
|
$type = '.gif';
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
if ($img === false) {
|
|
return false;
|
|
}
|
|
$croppedFileName = $GLOBALS['uploadDir'] . $newName . '_' . $fileNameWithoutExt . $type;
|
|
|
|
// Calculate the coordinates for the cropping
|
|
if ($originalWidth <= $targetWidth) {
|
|
$cropX = 0;
|
|
$targetWidth = $originalWidth;
|
|
} else {
|
|
$cropX = ($originalWidth - $targetWidth) / 2; // Crop from the center horizontally
|
|
}
|
|
if ($originalHeight <= $targetHeight) {
|
|
$cropY = 0;
|
|
$targetHeight = $originalHeight;
|
|
} else {
|
|
$cropY = ($originalHeight - $targetHeight) / 2; // Crop from the center vertically
|
|
}
|
|
|
|
switch ($imageType) {
|
|
case IMAGETYPE_JPEG:
|
|
// Create a new image with the cropped dimensions
|
|
$croppedImg = imagecrop($img, ['x' => $cropX, 'y' => $cropY, 'width' => $targetWidth, 'height' => $targetHeight]);
|
|
|
|
$quality = $GLOBALS['JPEG_quality'];
|
|
imagejpeg($croppedImg, $croppedFileName, $quality);
|
|
break;
|
|
case IMAGETYPE_PNG:
|
|
// Create a new true color image with the desired dimensions
|
|
$croppedImg = imagecreatetruecolor($targetWidth, $targetHeight);
|
|
|
|
// Enable transparency
|
|
imagealphablending($croppedImg, false);
|
|
imagesavealpha($croppedImg, true);
|
|
|
|
// Allocate a color for the background (fully transparent)
|
|
$transparentColor = imagecolorallocatealpha($croppedImg, 0, 0, 0, 127);
|
|
imagefill($croppedImg, 0, 0, $transparentColor);
|
|
|
|
// Copy the relevant portion of the source image to the new image
|
|
imagecopy($croppedImg, $img, 0, 0, $cropX, $cropY, $targetWidth, $targetHeight);
|
|
|
|
$compression = $GLOBALS['PNG_compression'];
|
|
// Save the cropped image
|
|
imagepng($croppedImg, $croppedFileName, $compression);
|
|
break;
|
|
case IMAGETYPE_GIF:
|
|
// Create a new image with the cropped dimensions
|
|
$croppedImg = imagecrop($img, ['x' => $cropX, 'y' => $cropY, 'width' => $targetWidth, 'height' => $targetHeight]);
|
|
|
|
$number_of_colors = $GLOBALS['GIF_number_of_colors'];
|
|
// Reduce the number of colors to make the file smaller
|
|
imagetruecolortopalette($croppedImg, false, $number_of_colors);
|
|
|
|
imagegif($croppedImg, $croppedFileName);
|
|
break;
|
|
}
|
|
|
|
// Free up memory
|
|
imagedestroy($img);
|
|
imagedestroy($croppedImg);
|
|
|
|
return $newName . '_' . $fileNameWithoutExt . $type;
|
|
}
|
|
|