Backend Development
PHP Tutorial
PHP image compression is invalid: in-depth analysis and correct practice
PHP image compression is invalid: in-depth analysis and correct practice

This tutorial aims to solve the common problem of file size not changing after PHP image compression. The core reason is that after the compression operation is completed, the original uncompressed file is mistakenly moved again and overwrites the compressed file. This article will reveal this problem through code analysis and provide the correct solution. It emphasizes that redundant file movement operations should be avoided when performing image processing to ensure that the compression results are preserved.
Root causes and solutions for PHP image compression failure
In web development, in order to optimize page loading speed and save storage space, it is a common requirement to compress images uploaded by users. However, developers sometimes encounter a confusing problem when using PHP for image compression: although the code logic seems correct, the image file size does not change. This article will delve into the reasons behind this phenomenon and provide a clear, professional solution.
Problem Analysis: Common Modes of Image Compression Failure
When a PHP script attempts to compress and save an image, if the compression function (such as imagejpeg or imagepng) successfully generates a compressed image file, but then performs an operation that moves the original uploaded file to the same destination path, the previous compression efforts will be wasted. The original, uncompressed temporary file will directly overwrite the compressed file just generated.
Consider the following common code snippet, which demonstrates this potential problem:
public function addcoverimageAction()
{
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// ... (other initialization and path setting code) ...
$directoryName = dirname(__DIR__) . "/images/$thisuser/listings/$postid/coverimage/";
if (!is_dir($directoryName)) {
mkdir($directoryName, 0777, true);
}
//Define the image compression function function compressImage($source, $destination, $quality)
{
$info = getimagesize($source);
$image = null;
if ($info['mime'] == 'image/jpeg') {
$image = imagecreatefromjpeg($source);
} elseif ($info['mime'] == 'image/png') {
$image = imagecreatefrompng($source);
} else {
// Handle other image types or errors return false;
}
if ($image) {
imagejpeg($image, $destination, $quality); // Save the compressed image to the target path imagedestroy($image); // Release memory return true;
}
return false;
}
// Call the compression function and save the compressed image to $directoryName . $filename
compressImage($_FILES['file']['tmp_name'], $directoryName . $filename, 60);
//! ! ! The problem: moving the original uploaded file to the same target path again, overwriting the compressed file move_uploaded_file($_FILES['file']['tmp_name'], $directoryName . $filename);
// ... (subsequent database updates and other operations) ...
}
// ... (other code) ...
}
In the above code, the compressImage function is responsible for reading the temporary upload file ($_FILES['file']['tmp_name']), processing it, and saving the compressed result to the specified target path ($directoryName . $filename) through imagejpeg (or imagepng). This is a correct compression and saving step.
However, the subsequent move_uploaded_file($_FILES['file']['tmp_name'], $directoryName . $filename); call is the root cause of the problem. The function of move_uploaded_file is to move the temporary file uploaded by the browser to its final location on the server. Since its target path is exactly the same as the path used by the compressImage function to save the compressed file, this operation will move the original, uncompressed temporary file to that location again, ruthlessly overwriting the previously generated compressed file. The result is that, although the compression operation does occur, the final file stored on the server is still the original size.
Solution: Remove redundant move_uploaded_file
The key to solving this problem is to understand that when your image processing function (such as compressImage) is already responsible for saving the processed image to the final destination path, there is no need to use move_uploaded_file to move the original temporary file. The imagejpeg (or imagepng) function itself contains the function of writing image data to a file.
Therefore, the correct approach is to remove redundant move_uploaded_file calls. The modified code example is as follows:
public function addcoverimageAction()
{
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Clean the POST array to prevent cross-site scripting attacks, etc. $_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
$userid = $this->route_params['userid'];
$postid = $this->route_params['postid'];
$path_parts = pathinfo($_FILES['file']['name']);
// It is recommended to generate a more secure unique file name, such as using hash value or UUID, and retain the original extension // The original code uses microtime(true) which may cause the file name to be too long or not as expected. Optimize here $filename = uniqid() . '.' . strtolower($path_parts['extension']);
$directoryName = dirname(__DIR__) . "/images/$userid/listings/$postid/coverimage/";
// Check and create directory if (!is_dir($directoryName)) {
// Ensure that the directory permissions are set appropriately. 0777 may be too loose. For production environments, it is recommended to use stricter permissions, such as 0755.
if (!mkdir($directoryName, 0755, true)) {
// Directory creation failure handling error_log("Failed to create directory: $directoryName");
// Can throw an exception or return an error message return;
}
}
//Define the image compression function function compressImage($source, $destination, $quality)
{
$info = getimagesize($source);
if ($info === false) {
error_log("Failed to get image size for: $source");
return false; // Unable to obtain image information}
$image = null;
switch ($info['mime']) {
case 'image/jpeg':
$image = imagecreatefromjpeg($source);
break;
case 'image/png':
$image = imagecreatefrompng($source);
break;
case 'image/gif': // Add support for GIF format $image = imagecreatefromgif($source);
break;
default:
error_log("Unsupported image type: " . $info['mime']);
return false; // Unsupported image type}
if ($image) {
$saveSuccess = false;
//Select the save function and adjust the quality parameters according to the MIME type if ($info['mime'] == 'image/jpeg') {
$saveSuccess = imagejpeg($image, $destination, $quality);
} elseif ($info['mime'] == 'image/png') {
// PNG compression quality range is 0-9, 9 is the highest quality (largest file), 0 is the lowest quality (smallest file)
//$quality here needs to be converted from 0-100 to 0-9
$pngQuality = round(($quality / 100) * 9);
$saveSuccess = imagepng($image, $destination, $pngQuality);
} elseif ($info['mime'] == 'image/gif') {
// GIF usually does not require quality parameters, just save it directly $saveSuccess = imagegif($image, $destination);
}
imagedestroy($image); // Release memory return $saveSuccess;
}
return false;
}
// Call the compression function and save the compressed image to the target path // Make sure the compression is successful before updating the database or performing subsequent operations if (compressImage($_FILES['file']['tmp_name'], $directoryName . $filename, 75)) { // Adjust the quality parameter to 75
// Compression successful, update database Post::updateCoverimage($filename, $postid);
// At this time, the original temporary file still exists in $_FILES['file']['tmp_name'], but it is usually automatically cleaned up by PHP at the end of the request // If you have special needs, you can also manually unlink($_FILES['file']['tmp_name']);
} else {
// Compression failure processing error_log("Image compression failed for user $userid, post $postid. Temp file: " . $_FILES['file']['tmp_name']);
// Error information can be returned to the user // For example: $this->view->assign('error', 'Image upload or compression failed');
}
}
// This part of the code may need to be adjusted based on actual business logic to ensure that the view can be correctly rendered even when non-POST requests or compression fails $this->post = Post::findByID($postid);
}
Things to note and best practices
- File naming security: The original code uses microtime(true) combined with the original file name as the new file name, which may result in too long file names or potential security risks. It's safer to generate a unique hash or UUID as the filename and keep the original extension. File extensions are always verified and sanitized to prevent malicious files from being uploaded.
- Directory permissions: The 0777 permissions in mkdir($directoryName, 0777, true); are too loose and may pose security risks. In a production environment, it is recommended to use more restrictive permissions, such as 0755, to ensure that only the server process has write permissions, and to handle errors when creating the directory fails.
- PNG compression quality: The quality parameter range of imagejpeg is 0-100, while the quality parameter range of imagepng is 0-9 (0 means the smallest file, 9 means the largest file). If the compressImage function handles both JPEG and PNG, the conversion of quality parameters needs to be adjusted according to the image type. The GIF format generally does not require quality parameters.
- Error handling: getimagesize, imagecreatefrom*, imagejpeg/imagepng and other functions may fail. In practical applications, appropriate error checking and handling mechanisms should be added, such as checking function return values, logging, and providing friendly error prompts to users.
- Memory management: After processing image resources, it is a good habit to use imagedestroy($image); to release memory, especially when processing a large number of images, to avoid memory overflow.
- Temporary file cleaning: PHP usually automatically cleans the temporary files pointed to by $_FILES['file']['tmp_name'] at the end of the request. But in some special cases, if you need to release it early or ensure cleanup, you can manually use unlink($_FILES['file']['tmp_name']);.
- Function encapsulation and reuse: It is not common to define the compressImage function as a local function inside a class method. It is usually defined as an independent auxiliary function, a class static method, or a method of an independent image processing service class to improve code reusability and maintainability.
- Image type extension: The sample code has been extended to support GIF format. In practical applications, all expected image formats should be supported on demand.
Summarize
The problem that the file size of PHP images does not change after compression is usually caused by the original uncompressed temporary file being moved again and overwriting the compressed file after the compression operation. The core of solving this problem lies in understanding the file processing process and avoiding redundant move_uploaded_file operations. By removing no
The above is the detailed content of PHP image compression is invalid: in-depth analysis and correct practice. For more information, please follow other related articles on the PHP Chinese website!
Hot AI Tools
Undress AI Tool
Undress images for free
AI Clothes Remover
Online AI tool for removing clothes from photos.
Undresser.AI Undress
AI-powered app for creating realistic nude photos
ArtGPT
AI image generator for creative art from text prompts.
Stock Market GPT
AI powered investment research for smarter decisions
Hot Article
Popular tool
Notepad++7.3.1
Easy-to-use and free code editor
SublimeText3 Chinese version
Chinese version, very easy to use
Zend Studio 13.0.1
Powerful PHP integrated development environment
Dreamweaver CS6
Visual web development tools
SublimeText3 Mac version
God-level code editing software (SublimeText3)
Hot Topics
20606
7
13699
4
How to implement Eloquent Attribute Accounting in PHP_Laravel data operation audit tracking [Tutorial]
Apr 14, 2026 am 06:45 AM
Adding logs directly to Eloquent's $casts or getFooAttribute is invalid because the accessor/mutator is only triggered when the model attributes are read and written, and cannot capture batch updates, native SQL and other changes that bypass the model. The audit needs to cover all data modification scenarios.
How to safely modify table names referenced by foreign keys in Laravel migrations
Apr 17, 2026 pm 01:22 PM
This article introduces how to safely update the target table name of an existing foreign key constraint (such as changing from seller to sellers) through migration in Laravel, covering the key steps and precautions for deleting old constraints and rebuilding new constraints.
NGINX URL redirection in action: detailed explanation and best practices
Apr 22, 2026 am 06:17 AM
This article aims to provide a professional tutorial on how to configure URL redirection using Nginx. We will focus on the use of the rewrite directive, especially how to redirect the root path to a URL with query parameters, and delve into the difference between the redirect (302 temporary redirect) and permanent (301 permanent redirect) flags and their considerations in SEO and browser caching to ensure that the Nginx configuration is both efficient and in line with best practices.
MySQL inventory entry and exit details and balance query (filtered by date and warehouse)
Apr 17, 2026 pm 01:34 PM
This article explains in detail how to use MySQL CTE and UNION ALL to build a dynamic inventory flow report, summarize the purchase (Purchase), outbound (Order) quantity and real-time balance of each commodity according to the specified date and warehouse ID, and output a structured result set that can be directly used for business dashboards.
How to implement lazy loading of images to improve long page performance
Apr 22, 2026 am 04:26 AM
This article introduces how to use the loading="lazy" attribute of native HTML to easily load images on demand in the viewport, significantly reducing initial page resource consumption. It is especially suitable for scrolling long pages such as portfolios and galleries containing a large number of images. No JavaScript framework required and compatible with modern mainstream browsers.
How to safely transcribe .PO files to Cyrillic and avoid NUL character pollution
Apr 17, 2026 pm 12:44 PM
This article explains in detail the root cause of NUL NUL NUL (null byte) garbled characters when processing .po localized files in PHP, and provides a repair solution based on safe file stream operations. It emphasizes avoiding direct reading and writing of the same file, and recommends using a professional PO parsing library instead of manual string replacement.
Correctly loading related models in Laravel: Use with() to preload users and their posts
Apr 28, 2026 am 06:10 AM
In Laravel, if you need to get a specified user based on ID and preload its associated posts at the same time, you must put with() before findOrFail(); otherwise, findOrFail() will immediately execute the query and return a single model, and subsequent with() and first() will fail or produce unexpected results.
How to safely output the string 'null' instead of an empty value in PHP
Apr 28, 2026 am 06:39 AM
In PHP 8, when the variable value is null, echo directly will output empty content; this article introduces a variety of safe and concise methods (such as the null coalescing operator, ternary abbreviation, etc.) to make the null value explicitly displayed as the string "null".





