In this blog post, we will demonstrate how to perform common image optimizations on a web application built on PHP. We will leverage the Abstract Image Processing and Optimization API to build a demo app that can upload images, and further, resize or compress them. These are two of the most fundamental image-processing tasks required on any web application that manages images.

If you haven’t signed up for your free Abstract account to access this API, check out the API overview below. Else you can skip over to the next section where we take you through the steps to build the demo app for PHP using the Laravel framework.

Overview of Abstract Image Processing and Optimization API

The Image Processing and Optimization API is part of Abstract API’s catalog of APIs for content creators. It supports quick and easy optimization of images for resizing and compressing images. This API can also crop and add background fill to images. 

To get started with this API, signup for your AbstractAPI account and head over to the Images API dashboard, where you can see your API key.

This API offers a free quota of 100 MB uploaded file size of images per month, which should be good enough for you to play around with its capabilities. 

For resizing images, the API allows you to pass a width and height parameter, along with the strategy for aspect ratio. In the case of compression, you can pass a quality score to decide the final quality of the image. Follow the documentation to know more about all the API request parameters and their significance. 

Don't reinvent the wheel.
Abstract's APIs are production-ready now.

Abstract's suite of API's are built to save you time. You don't need to be an expert in email validation, IP geolocation, etc. Just focus on writing code that's actually valuable for your app or business, and we'll handle the rest.

Get started for free

Building the Demo App for PHP Image Upload and Optimization

This demo app demonstrates image file upload operation via an HTML form and also allows the user to perform resize or compress operations. Both the original uploaded image and the optimized image are shown on the UI with their respective file sizes. 

The app is built on the Laravel PHP framework and leverages the Abstract API behind the scenes, to process the images. The HTML view of the app takes the user inputs for uploading the image file and presents a form to input further parameters based on the desired action, “Resize” or “Compress”.  

Before proceeding further, here are a few prerequisites for the development environment for building this demo app in PHP code.

Prerequisites

  1. PHP and Laravel: Make sure you have a PHP 8 runtime available with Laravel. You can install Laravel with the composer package manager.
  2. Imgur Account: You will need an Imgur account to host the uploaded file for images to be processed. Signup for an account on Imgur. You will also need the Imgur API access by registering a client application. To do that, open the Imgur registration page:
  1. And fill in the following details
  2. Application name: image upload
  3. Authorization: OAuth2 Authorization with a callback URL
  4. Redirect URL: https://int.bearer.sh/v2/auth/callback
  5. Email: Provide any email address 

  6. Once submitted, you will get an Imgur Client Id and a secret. Make a note of these two credentials.
  7. Create a new Laravel project named image-resize with this composer command executed from a terminal
  8.             composer create-project --prefer-dist laravel/laravel image-upload
  9. This will create a directory named image-upload under the present working directory where the command is executed. This is the project directory of this demo app containing all the boilerplate code and dependencies. Make sure to change to this directory for executing all further commands from the terminal.   
  10. Open your favorite IDE and check out the directory structure of the project directory

Step 1: Test the Default Laravel App

Following the prerequisites, you should be able to test the default Laravel by launching it from the terminal.


php artisan serve

This will start a development web server that hosts the default Laravel app at https://127.0.0.1:8000

Step 2: Add the API Keys for Demo App

Open the environment file for the project and add two new environment variable entries for the Imgur Client ID and Abstract API key.

File: .env


IMGUR_SECRET=<YOUR_IMGUR_CLIENT_ID>
ABSTRACT_SECRET=<YOUR_ABSTRACTAPI_KEY>

Step 3: Add the HTTP helper classes for Imgur and Abstract API

Create two helper classes, Imgur.php and AbstractAPI.php under the Http subdirectory.

File: app/Http/Helpers/Imgur.php


<?php
namespace App\Http\Helpers;

class Imgur
{
    public function upload($image)
    {
        // base64 encode image
        $image = base64_encode(file_get_contents($image));

        $curl = curl_init();

        curl_setopt_array($curl, array(
            CURLOPT_URL => 'https://api.imgur.com/3/image',
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => '',
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_POSTFIELDS => array('image' => $image),
            CURLOPT_HTTPHEADER => array(
                'Authorization: Client-ID '.env('IMGUR_SECRET')
            ),
        ));

        $response = curl_exec($curl);

        curl_close($curl);

        return json_decode($response, true, JSON_THROW_ON_ERROR);
    }
}

File:  app/Http/Helpers/AbstractAPI.php


<?php
namespace App\Http\Helpers;

use Illuminate\Support\Facades\Http;

class AbstractAPI
{
    public function formatImage(array $data)
    {

        $res = Http::withHeaders([
            "Content-Type" => "application/json",
        ])->post('https://images.abstractapi.com/v1/url/', $this->buildData($data));

        return $res->json();

    }


    private function buildData(array $data)
    {
        if ($data['action'] == 'resize') {
            return $data = [
                'api_key' => env('ABSTRACT_SECRET'),
                'resize' => [
                    'width' => $data['width'],
                    'height' => $data['height'],
                    'strategy' => 'exact',
                ],
                'url' => $data['url'],
            ];
        }else {
            return $data = [
                'api_key' => env('ABSTRACT_SECRET'),
                'lossy' => true,
                'quality' => $data['quality'],
                'url' => $data['url'],
            ];
        }

    }
}

These two helper classes handle the API calls for Imgur and AbstractAPI respectively.

The Imgur.php php file uploads an image from the demo app to host it as an URL. This URL is input to AbstractAPI.php php file which calls the Image Processing and Optimization API. This API returns the resized or compressed image in the API response as per the action chosen by the user. The optimized image is available as another URL hosted by Abstract API.

Step 4: Add a New Controller Named ImageController

From the terminal, add a new controller named ImageController.


php artisan make:controller ImageController

This will create a new PHP script file app/Http/Controllers/ImageController

Replace the default content of the file with the following code:


<?php

namespace App\Http\Controllers;

use App\Http\Helpers\AbstractAPI;
use App\Http\Helpers\Imgur;
use Illuminate\Http\Request;

class ImageController extends Controller
{
    public function index()
    {
        return view('welcome');
    }

    public function upload(Request $request)
    {
        $valid = $request->validate([
            'image' => 'required|image|mimes:jpeg,png,jpg,gif,svg|max:2048',
            'action' => 'required|string|in:resize,compress',
            'width' => 'required_if:action,resize|numeric',
            'height' =>'required_if:action,resize|numeric',
            'quality' => 'required_if:action,compress|numeric'
        ]);

        try {

            $imgur = (new Imgur())->upload($request->file('image'));

            // get the image link
            if ($imgur['success'] === true || $imgur['status'] === 200) {
                $valid['url'] = $imgur['data']['link'];
                // send image link to abstract api
                $abstract = (new AbstractAPI())->formatImage($valid);

                return response()->json($abstract);
            }
                return response()->json([
                'success' => false,
                'message' => 'Something went wrong',
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => $e->getMessage(),
            ]);
        }

    }
}

This controller defines a custom API endpoint called upload. This API accepts the image from the UI and calls Imgur and AbstractAPI sequentially to return the optimized image.

This controller also defines the home page view for the UI.

Step 5: Update the App Routes

You must register the routes for the demo app in Laravel. There are only two routes, ‘/’ and ‘/upload’ for displaying the web page for demo app and uploading the images, respectively.

Replace the content of the routes definition under routes/web.php.


<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', [App\Http\Controllers\ImageController::class, 'index'])->name('home');
Route::post('/upload', [App\Http\Controllers\ImageController::class, 'upload'])->name('upload');

Step 6: Create the HTML and JavaScript for the Demo App UI

At this point, all the backend PHP logic is built for the demo app. Now the last thing is the HTML page. You can use the default HTML view of the Laravel app under resources/view/welcome.blade.php and replace its content with:


<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>PHP Upload Demo App</title>

        <!-- Fonts -->
        <link href="https://fonts.bunny.net/css2?family=Nunito:wght@400;600;700&display=swap" rel="stylesheet">
        <!-- CSS only -->
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
    </head>
    <body>
        <nav class="navbar bg-light">
            <div class="container-fluid">
                <span class="navbar-brand mb-0 h1">PHP Upload Demo App</span>
        </div>
        </nav>
        <div class="container">
            <div class="row align-items-center justify-content-center">
                <div class="col-md-8 col-offset-2 mt-5">
                    <div class="card">
                        <div class="card-header">
                            <h3>PHP Upload and Optimize Image</h3>
                        </div>
                        <div class="card-body">
                            <form id="imageForm">
                                @csrf
                                <div class="input-group mb-3">
                                    <label class="input-group-text" for="image">Upload</label>
                                    <input type="file" class="form-control" onchange="previewFile(this);" id="image" name="image" required>
                                </div>

                                <div class="row mb-3">
                                    <label for="action">Action</label>
                                    <select name="action" id="action" class="form-control" required>
                                        <option selected>Choose an Action</option>
                                        <option value="resize">Resize</option>
                                        <option value="compress">Compress</option>
                                    </select>
                                </div>

                                <div class="row mb-3" id="qualityTab" style="display: none;">
                                    <label for="quality">Quality</label>
                                    <input type="number" name="quality" id="quality" class="form-control" disabled>
                                </div>

                                <div class="row mb-3" id="sizeTab" style="display: none;">
                                    <div class="col">
                                        <label for="width">Width</label>
                                        <input type="number" class="form-control" id="width" name="width" disabled>
                                    </div>
                                    <div class="col">
                                        <label for="width">Height</label>
                                        <input type="number" class="form-control" id="height" name="height" disabled>
                                    </div>
                                </div>
                                <div class="row mb-3">
                                    <div class="col" id="current_image" style="display: none;">
                                        <label for="">Original Image</label><br/>
                                        <img src="" id="original_image" class="img-fluid" alt=""><br/>
                                        <small id="original_image_size"></small>
                                    </div>
                                    <div class="col" id="new_image" style="display: none;">
                                        <label for="">New Image</label><br/>
                                        <img src="" id="resized_image" class="img-fluid" alt=""></br>
                                         <small id="resized_image_size"></small>
                                    </div>
                                </div>
                                <div class="row mb-3 text-center">
                                    <div class="col">
                                        <button type="submit" id="submit" class="btn btn-primary">Submit</button>
                                    </div>
                                    <div class="col">
                                        <button type="reset" id="reset" class="btn btn-danger">Reset</button>
                                    </div>
                                </div>
                            </form>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js" integrity="sha512-aVKKRRi/Q/YV+4mjoKBsE4x3H+BkegoM/em46NNlCqNTmUYADjBbeNefNxYV7giUp0VxICtqdrbqU7iVaeZNXA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <!-- JavaScript Bundle with Popper -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3" crossorigin="anonymous"></script>
    <script>
        $("#reset").click(function(){
            $("#original_image").attr("src", "");
            $("#current_image").hide();
            $("#resized_image").attr("src", "");
            $("#new_image").hide();
        });

        $("#action").change(function(){
            var value = $(this).val();
            if(value == 'resize') {
                $("#sizeTab").show()
                $("#qualityTab").hide()

                $("#width").prop("disabled", false);
                $("#height").prop("disabled", false);
                $("#quality").prop("disabled", true);
                return;
            }else{
                $("#qualityTab").show()
                $("#sizeTab").hide()

                $("#width").prop("disabled", true);
                $("#height").prop("disabled", true);
                $("#quality").prop("disabled", false);
                return;
            }
        });

        function previewFile(input){
            $("#current_image").hide();
        var file = $("input[type=file]").get(0).files[0];

        if(file){
            $("#current_image").show();
            var reader = new FileReader();

            reader.onload = function(){
                $("#original_image").attr("src", reader.result);
            }

            reader.readAsDataURL(file);
            $("#original_image_size").text(file.size/1000 + " KB");
        }
    }

    $("#imageForm").submit(function(e){
        e.preventDefault();
        $("#submit").html('<div class="spinner-border text-danger" id="status" role="status"><span class="visually-hidden">Loading...</span></div>');
        $("#new_image").hide();
        var formData = new FormData(this);
        $.ajax({
            url: "{{ url('/upload') }}",
            type: 'POST',
            data: formData,
            success: function (data) {
                $("#resized_image").attr("src", data.url);
                $("#new_image").show();
                $("#resized_image_size").text(data.final_size/1000 + " KB");
                $("#submit").html('Submit');
            },
            error: function(data){
                $("#submit").html('Submit');
                console.log(data);
            },
            cache: false,
            contentType: false,
            processData: false
        });
    });
    </script>
    </body>
</html>

This is a Bootstrap based HTML upload form that lets the user upload an image. Further, it offers two actions for resizing and compressing the images.

With this, all the code changes for the demo app are done. Make sure to save all the files.

Step 7: Relaunch the Laravel Server

Relaunch the Laravel development server and now you should see the demo app UI.

Step 8: Test the Demo App

Now you are ready to test the app. Upload any images from your computer and submit the form by choosing the “Resize’ action and specifying the desired width and height.

Once the Abstract API processes the image, the newly resized image will be displayed along with the target image size.

Similarly, you can also choose the “Compress” action and specify a quality score. By choosing a low score, you can achieve high compression of the image.

However, you may notice a slight deterioration of the image quality. Therefore, you have to choose the quality score that optimally balances the image size and the visual perception of the image quality.

We are done!

We set out to build this demo app to enable any PHP Laravel based web application to perform image resizing and compression on its own. And we have achieved it now.

The AbstractAPI Image Processing and Optimization API is a great alternative to the built-in PHP image processing libraries and does the job pretty well, while seamlessly integrating with the app logic and frontend UI.

FAQs

How do I compress an image file in PHP?

You can achieve image file compression in PHP using one of the built-in extensions such as Imagick or the GD library. However, if you want to offload the burden of image processing from your server-side application logic, then it’s best to use an image compression API. Abstract API Image Processing and Optimization API is best suited for this job. This API supports image compression through the standard quality score that ranges from 0 to 100. You can signup for Abstract API and try out this API for free to test its features. 

How to upload images in Laravel?

Laravel is a PHP framework and it supports the default PHP image upload features. For uploading files, you would typically use the POST method to submit an HTML form with <input> element that contains the file path and read it at the PHP end using $_FILES. Alternatively, you can use a cloud-hosted service API to upload an image file to one of the services such as Amazon S3 or Imgur.

How to resize an image file in PHP?

You can achieve image resizing in PHP using one of the built-in extensions such as Imagick or the GD library. However, if you want to offload the burden of image processing from your server-side application logic, then it’s best to use an image compression API. Abstract API Image Processing and Optimization API is best suited for this job. This API supports image resizing through the height and width parameters and also allows you to set the aspect ratio. You can signup for Abstract API and try out this API for free to test any jpeg or png file. 

Try Abstract's free Image Optimization API today.

Get started for free
Try Abstract's free Image Optimization API today.
Get started