PHP/JavaScript Uploader
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.
 
 
 
uploads/image_compression.php

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;
}