There is.htaccess
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} \.[0-9]{2,3}x[0-9]{2,3}\.(jpg|jpeg|png|gif)$
RewriteRule ^(.*)$ image.php [L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L]
</IfModule>
There is image.php
<?php
// Error Logging Management
error_reporting(0);
// Client Request
$request = parse_url($_SERVER['REQUEST_URI'])['path'];
// Parsing the client's request into parts
// It is acceptable to specify width and height values from 10 to 999,
// this is done in order to protect the server from requests like: [9999x9999],
// which in turn will entail the consumption of huge resources.
if (preg_match('/(.*?)\.([0-9]{2,3}) x([0-9]{2,3})\.( jpg|jpeg|png|gif)$/i', $request, $match))
{
// Part of the path without extension, installation width and height, as well as image extension
list(, $way_part, $set_width, $set_height, $extension) = $match;
// Absolute path to the image
if ($path = realpath(__DIR__ . $way_part . '.' . $extension))
{
// Real width and height
of the list image($src_width, $src_height) = getimagesize($path);
// Calculation required for correct CROP
$x = $y = 0;
$crop_width = $src_height * $set_width / $set_height;
$crop_height = $src_width * $set_height / $set_width;
if ($crop_width < $src_width)
{
$x = ($src_width - $crop_width) / 2;
$src_width = $crop_width;
}
else
{
$y = ($src_height - $crop_height) / 2;
$src_height = $crop_height;
}
// Performing all necessary operations to create a new image with the set width and height, and output it to the browser
switch (strtolower($extension))
{
case 'jpg' :
case 'jpeg' :
// Generating a response informing the client about the MIME type of the image
header('Content-Type: image/jpeg');
// Creating a new full-color image
// Returns an image ID representing a black image of the specified size
$new = imagecreatetruecolor($set_width, $set_height);
// Copying and resizing an image with resampling
// If the coordinates, width or height of the source and destination images are different, the copied fragment will be stretched or compressed
// Coordinates are counted from the upper-left corner of the image
imagecopyresampled($new, imagecreatefromjpeg($path), 0, 0, $x, $y, $set_width, $set_height, $src_width, $src_height);
// Outputs the image to the browser
imagejpeg($new, NULL, 100);
// Image Destruction
imagedestroy($new);
break;
// For the rest of the extensions, I deleted sections of the code so as not to bother your eyes ...
}
// Normal exit from the program
exit(1);
}
}
// Forming a response informing the client about the 404 error
header('HTTP/1.0 404 Not Found');
// Exiting the program with an error
exit(0);
As everything seemed to be working fine during local development, issues arose when testing the script on the hosting site as the server took a significant amount of time to output the images.
A workaround for this is using a script that works locally by accessing the image with a specific size parameter, for example, 1.100x100.jpg for a required 100x100 size.
The main question here is about ideas to optimize the script and enhance the speed of image output on the server, considering that only PHP can be used as there is no terminal access.
It is worth mentioning that disk space is a limitation with approximately 20 gigabytes of images already. To save space, in some sections, two versions of the image are created - the original and a 300x300 version. This allows for less memory consumption when cropping images on the fly.
I would like to express my gratitude to everyone participating in this discussion.
Here are a few suggestions to optimize the script and improve the speed of image output on the server:
1. Use caching: Implement caching mechanisms to store processed images temporarily. When an image is requested, check if it already exists in the cache before processing it again. This can significantly reduce the processing time for subsequent requests.
2. Avoid unnecessary file operations: Reduce disk I/O operations by checking if the processed image already exists before creating a new one. If it does exist, serve the existing image directly instead of re-creating it.
3. Optimize image resizing: Consider using a more efficient image resizing algorithm, such as Lanczos or Bicubic interpolation, instead of the default imagecopyresampled function. These algorithms produce better quality results with less memory consumption.
4. Use image compression: Apply image compression techniques, such as reducing the image quality or converting to a more compressed format like WebP, to further reduce file size and improve loading speed.
5. Use a CDN: Consider using a content delivery network (CDN) to serve your images. CDNs have servers located worldwide and can deliver the images from the server closest to the user, reducing latency and improving loading speed.
6. Enable HTTP compression: Enable Gzip compression on your server to compress the response before sending it to the client. This can significantly reduce the file size and improve transfer speed.
7. Profile and optimize your code: Use a profiler to identify performance bottlenecks in your code and optimize those areas. Look for any redundant calculations or unnecessary code that can be removed or optimized.
8. Lazy loading: Implement lazy loading techniques, where images are loaded only when they come into the viewport of the user's browser. This can significantly improve the initial page load time by reducing the number of images that need to be loaded at once.
9. Use a lightweight PHP framework: Consider using a lightweight PHP framework, such as Slim or Lumen, to handle the routing and request-response cycle. These frameworks are designed to be fast and efficient, which can help improve the overall performance of your application.
10. Utilize image caching plugins: If you're using a CMS like WordPress, there are various image caching plugins available that can help optimize the delivery of images. These plugins generate optimized versions of the images and serve them directly, reducing the processing time.
11. Optimize database queries: If your script interacts with a database, make sure to optimize your database queries. Use indexes, limit the number of retrieved rows, and consider caching frequently accessed data to minimize the impact of database operations on performance.
12. Optimize server configuration: Check your server configuration settings, such as memory_limit and max_execution_time, and make sure they are set appropriately to handle image processing efficiently. You can consult with your hosting provider or system administrator to fine-tune these settings.
13. Parallelize image processing: If possible, parallelize image processing by utilizing multiple threads or processes. This can be achieved by employing techniques such as task queue systems or multi-threading libraries.
14. Load test and monitor performance: Regularly perform load testing on your application to identify any performance bottlenecks and ensure that the optimizations you implement are effective. Use monitoring tools to track server response times, CPU and memory usage, and other performance metrics.
Regarding the code you provided, here are a few specific suggestions to optimize it:
1. Error Reporting: Instead of setting `error_reporting(0)` to suppress errors, configure proper error reporting and handling. Errors can provide valuable insights into any issues or bottlenecks in your script.
2. Avoid Regular Expressions for Simple Parsing: Instead of using regular expressions to parse the client's request, consider using built-in string functions like `strpos` or `substr` which are generally faster and more efficient for simple parsing tasks.
3. Optimize Image Creation: Instead of creating two versions of the image (original and 300x300), consider generating the required size on-the-fly using image manipulation functions like `imagecopyresampled`. This can reduce disk space consumption and eliminate the need to maintain multiple versions of the same image.
4. Evaluate Image Formats: Depending on the specific use case and image content, you might consider converting images to a more efficient format like WebP, which typically offers smaller file sizes without significantly compromising image quality.
5. Implement HTTP Caching Headers: Add appropriate caching headers like `Cache-Control` and `Expires` to enable client-side caching of images. This can reduce server load and improve performance by allowing browsers to cache and serve images locally.
6. Use FastCGI: If you have control over the server environment, consider using FastCGI instead of traditional CGI for PHP script execution. FastCGI maintains persistent connections and caches compiled PHP scripts, resulting in improved performance and reduced overhead.
7. Benchmark and Profile: Use benchmarking tools like Apache Bench or Siege to measure the performance of your script under different load conditions. Additionally, use a profiler like Xdebug or Blackfire to identify any areas of your code that may be causing performance bottlenecks.
There are two immediate ways you can consider:
1) One option is to cache the results of the script execution. This means saving the cropped images to a file. When you need to retrieve an image, check if the file already exists and if it does, serve it directly.
2) Another approach is to enhance the image generation algorithm. For instance, you may consider using ImageMagick instead of GD since it operates more efficiently. Before proceeding, make sure to check if your hosting supports imagick or magickwand modules. However, keep in mind that this will require rewriting the code responsible for image generation.
Only by caching images that have already been processed can you save resources. You can configure RewriteCond to check if such a file exists. Don't prioritize saving HDD space at the expense of CPU time, as CPU time is more valuable. Otherwise, your server's limited resources will be wasted on unnecessary image cropping operations.
However, this caching method may not be effective if each request for an image is unique. For example, if the optimal image size for a block is calculated using JavaScript on your frontend and a new image is generated for each request. In such cases, it may be easier to create 2-3 versions of the same image and handle the variations using CSS on the frontend.