PHPackages                             ambroisemaupate/intervention-request - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Image &amp; Media](/categories/media)
4. /
5. ambroisemaupate/intervention-request

ActiveLibrary[Image &amp; Media](/categories/media)

ambroisemaupate/intervention-request
====================================

A customizable Intervention Image wrapper to use image simple re-sampling features over urls and a configurable cache.

v7.0.2(9mo ago)4242.4k↓43.5%7[1 issues](https://github.com/ambroisemaupate/intervention-request/issues)2MITPHPPHP &gt;=8.2

Since May 25Pushed 9mo ago4 watchersCompare

[ Source](https://github.com/ambroisemaupate/intervention-request)[ Packagist](https://packagist.org/packages/ambroisemaupate/intervention-request)[ RSS](/packages/ambroisemaupate-intervention-request/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (20)Versions (57)Used By (2)

Intervention Request
====================

[](#intervention-request)

**A customizable *Intervention Image* wrapper to use image simple re-sampling features over urls and a configurable cache.**

[![Static analysis and code style](https://github.com/ambroisemaupate/intervention-request/actions/workflows/run-test.yml/badge.svg)](https://github.com/ambroisemaupate/intervention-request/actions/workflows/run-test.yml)[![Packagist](https://camo.githubusercontent.com/4d66cf5c0585ff8a54362b846ce45cc5af61d40e15fe9f72d107e4d476a64e14/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f616d62726f6973656d6175706174652f696e74657276656e74696f6e2d726571756573742e737667)](https://packagist.org/packages/ambroisemaupate/intervention-request)[![Packagist](https://camo.githubusercontent.com/2d440badc970f16591c21dd483e782f6f32b141e8f8de317a57b623e756dbf4b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f616d62726f6973656d6175706174652f696e74657276656e74696f6e2d726571756573742e737667)](https://packagist.org/packages/ambroisemaupate/intervention-request)

- [Ready-to-go *Docker* image](#ready-to-go-docker-image)
    - [Use local file-system or a distant one](#use-local-file-system-or-a-distant-one)
    - [Docker Compose example](#docker-compose-example)
- [Install](#install)
- [Configuration](#configuration)
- [Available operations](#available-operations)
    - [Fit position](#fit-position)
- [Using standalone entry point](#using-standalone-entry-point)
- [Using as a library inside your projects](#using-as-a-library-inside-your-projects)
- [Use URL rewriting](#use-url-rewriting)
    - [Shortcuts](#shortcuts)
- [Use pass-through cache](#use-pass-through-cache)
- [Convert to webp](#convert-to-webp)
- [Force garbage collection](#force-garbage-collection)
    - [Using command-line](#using-command-line)
- [Extend Intervention Request](#extend-intervention-request)
    - [Add custom event subscribers](#add-custom-event-subscribers)
        - [Available events](#available-events)
        - [Listener examples](#listener-examples)
- [Performances](#performances)
- [Optimization](#optimization)
    - [jpegoptim](#jpegoptim)
    - [pngquant](#pngquant)
    - [oxipng](#oxipng)
    - [pingo](#pingo)
    - [kraken.io](#krakenio)
    - [tinyjpg.com](#tinyjpgcom)
    - [jpegtran](#jpegtran)
    - [Optimization benchmark](#optimization-benchmark)
- [Testing](#testing)
    - [Disable cache during development](#disable-cache-during-development)
    - [Test grid](#test-grid)
    - [Unit tests](#unit-tests)
        - [Test Strategy](#test-strategy)
        - [Running the Tests](#running-the-tests)
    - [Functional tests](#functional-tests)
        - [Test Strategy](#test-strategy-1)
        - [Running the Tests](#running-the-tests-1)
- [License](#license)

Ready-to-go *Docker* image
--------------------------

[](#ready-to-go-docker-image)

Intervention Request is now available as a standalone Docker server to use with whatever CMS or language you need. It declares two volumes: one for your images storage and one for cached files.

- `/app/public/images`: you can set it as read-only to prevent any write operation
- `/app/public/assets`: you must set it as read-write to allow cache files to be written

```
docker pull ambroisemaupate/intervention-request;
# Make sure to share your volume with READ-ONLY flag
docker run -v "/my/images/folder:/app/public/images:ro" -p 8080:80/tcp ambroisemaupate/intervention-request;
```

- Create a `/my/images/folder/your-image.png`
- Then try

Garbage collector runs every hour as a `crontab` job and will purge cache files created more than `$IR_GC_TTL` seconds ago. You still can execute it manually using `docker compose exec -u www-data intervention bin/intervention gc:launch` command.

### Use local file-system or a distant one

[](#use-local-file-system-or-a-distant-one)

*InterventionRequest* is built on [*Flysystem*](https://flysystem.thephpleague.com/docs/) library to abstract access to your native images. Then you can store all your images on an *AWS* bucket or a *Scaleway* Object Storage and process them on the fly. **Processed images are still cached on *InterventionRequest* local storage.** This new file system abstraction layer allows multiple *InterventionRequest* docker containers to run in parallel but still use the same storage as image backend, or simply detach your media storage logic from *InterventionRequest* application.

`InterventionRequest` object requires a `FileResolverInterface` which can be a `LocalFileResolver` or `FlysystemFileResolver`, then `FlysystemFileResolver` must be provided a `League\Flysystem\Filesystem` object configured with any *Flysystem* adapter.

If you prefer to use `ambroisemaupate/intervention-request` Docker image, environment variables are available for *AWS* adapter only.

### Docker Compose example

[](#docker-compose-example)

```
version: '3'
services:
    intervention:
        image: ambroisemaupate/intervention-request:7.0.2
        #image: ambroisemaupate/intervention-request:frankenphp-7.0.2
        volumes:
            - cache:/app/public/assets
            ## If using local storage file system
            - ./my/images/folder:/app/public/images:ro
        # You can override some defaults below
        environment:
            IR_DEBUG: 0
            IR_DEFAULT_QUALITY: 80
            ## If using local storage file system
            IR_IMAGES_PATH: /app/public/images
            ## If using an AWS or Scaleway Object storage file system
            IR_AWS_ACCESS_KEY_ID: 'changeme'
            IR_AWS_ACCESS_KEY_SECRET: 'changeme'
            IR_AWS_ENDPOINT: 'https://s3.fr-par.scw.cloud'
            IR_AWS_REGION: 'fr-par'
            IR_AWS_BUCKET: 'my-bucket'
            IR_AWS_PATH_PREFIX: 'images'
        ports:
            - 8080:80/tcp
        # Uncomment lines below for Traefik usage
        #labels:
        #    - "traefik.enable=true"
        #    - "traefik.http.services.intervention.loadbalancer.server.scheme=http"
        #    - "traefik.http.services.intervention.loadbalancer.server.port=80"
        #    - "traefik.http.services.intervention.loadbalancer.passhostheader=true"
        #    # Listen HTTP
        #    - "traefik.http.routers.intervention.entrypoints=http"
        #    - "traefik.http.routers.intervention.rule=Host(`intervention.test`)"
        #    - "traefik.http.routers.intervention.service=intervention"
        #networks:
        #    - default
        #    - frontproxynet
volumes:
    cache:
```

You don’t need to read further if you do not plan to embed this library in your PHP application.

Install
-------

[](#install)

```
composer require ambroisemaupate/intervention-request
```

Intervention Request is based on *symfony/http-foundation* component for handling HTTP request, response and basic file operations. It wraps [*Intervention/image*](https://github.com/Intervention/image)feature with a simple file cache managing.

Configuration
-------------

[](#configuration)

Intervention request use a dedicated class to configure your image request parameters. Before creating `InterventionRequest` object, you must instantiate a new `AM\InterventionRequest\Configuration` object and set cache and images paths.

```
$conf->setCachePath(APP_ROOT.'/cache');
$conf->setImagesPath(APP_ROOT.'/images');
```

This code will create a configuration with *cache* and *images* folders in the same folder as your PHP script (`APP_ROOT`). **Notice that in the default `index.php` file, *images* path is defined to `/test` folder in order to use the testing images**. You should always set this path against your website images folder to prevent processing other files.

You can edit each configuration parameters using their corresponding *setters*:

- `setCaching(true|false)`: use or not request cache to store generated images on filesystem (default: `true`);
- `setCachePath(string)`: image cache folder path;
- `setUsePassThroughCache(true|false)`: use or not *pass-through* cache to by-pass PHP processing once image is generated;
- `setDefaultQuality(int)`: default 90, set the quality amount when user does not specify it;
- `setImagesPath(string)`: requested images root path;
- `setTtl(integer)`: cache images time to live for internal garbage collector (default: `1 week`);
- `setResponseTtl(integer)`: image HTTP responses time to live for browser and proxy caches (default: `1 year`);
- `setDriver('gd'|'imagick')`: choose an available *Image Intervention* driver;
- `setTimezone(string)`: PHP timezone to build \\DateTime object used for caching. Set it here if you have not set it in your `php.ini` file;
- `setGcProbability(integer)`: Garbage collector probability divisor. Garbage collection launch probability is 1/$gcProbability where a probability of 1/1 will launch GC at every request.
- `setUseFileChecksum(true|false)`: Use file checksum to test if file is different even if its name does not change. This option can be greedy on large files. (default: `false`).
- `setJpegoptimPath(string)`: *Optional* — Tells where `jpegoptim` binary is for JPEG post-processing (not useful unless you need to stick to 100 quality).
- `setPngquantPath(string)`: *Optional* — Tells where `pngquant` binary is for PNG post-processing. **This post-processing tool is highly recommended** as PNG won’t be optimized without it.
- `setLossyPng(true|false)`: *Optional* — Tells `pngquant`/`pingo` binaries to use *palette* lossy compression (default: `false`).

Available operations
--------------------

[](#available-operations)

Query attributeDescriptionUsageimageNative image path relative to your configuration `imagePath``?image=path/to/image.jpg`fit[Crop and resize combined](https://image.intervention.io/v3/modifying-images/resizing#fitted-resizing-without-exceeding-the-original-size) It needs a `width` and a `height` in pixels,
this filter can be combined with `align` to choose which part of your image to fit`…&fit=300x300`align[Crop and resize combined](https://image.intervention.io/v3/modifying-images/resizing#fitted-resizing-without-exceeding-the-original-size) Choose which part of your image to fit.`…&align=c`flip[Mirror image horizontal or vertical](https://image.intervention.io/v3/modifying-images/effects#mirror-image-horizontally) You can set `h` for horizontal or `v` for vertical flip.`…&flip=h`crop[Crop an image](https://image.intervention.io/v3/modifying-images/resizing#crop-image) Crop and image by a **ratio** , using origin image size.`…&crop=1:1`width[Resize image proportionally to given width](https://image.intervention.io/v3/modifying-images/resizing#scale-images-but-do-not-exceed-the-original-size) It needs a `width` in pixels`…&width=300`height[Resize image proportionally to given height](https://image.intervention.io/v3/modifying-images/resizing#scale-images-but-do-not-exceed-the-original-size) It needs a `height` in pixels`…&height=300`crop + height/widthDo the same as *fit* using width or height as final size. Ex: this will output a 200 x 200px image`…&crop=1:1&width=200`background[Matte a png file with a background color](https://image.intervention.io/v3/basics/colors#merge-transparent-areas-with-color)`…&background=ff0000`greyscale/grayscale[Turn an image into a greyscale version](https://image.intervention.io/v3/modifying-images/effects#convert-image-to-a-greyscale-version)`…&greyscale=1`blur[Blurs an image](https://image.intervention.io/v3/modifying-images/effects#blur-effect)`…&blur=20`qualitySet the exporting quality (1 - 100), default to 90`…&quality=95`progressive[Toggle progressive mode](https://image.intervention.io/v3/basics/image-output#encode-images-by-media-mime-type)`…&progressive=1`interlace[Toggle interlaced mode](https://image.intervention.io/v3/basics/image-output#encode-images-by-media-mime-type)`…&interlace=1`sharpen[Sharpen image](https://image.intervention.io/v3/modifying-images/effects#sharpening-effect) (1 - 100)`…&sharpen=10`contrast[Change image contrast](https://image.intervention.io/v3/modifying-images/effects#change-the-image-contrast) (-100 to 100, 0 means no changes)`…&contrast=10`no\_process**Disable all image processing by PHP**, this does not load image in memory but executes
 any post-process optimizers (such as *pngquant*, *jpegoptim*…)`…&no_process=1`hotspot[Crop an image](https://image.intervention.io/v3/modifying-images/resizing#crop-image) using a center point and a base area equal to original image.
It needs a `x`, `y` (to define the center point of the image in percentage between 0 and 1).
[Since v6.0.0](https://github.com/ambroisemaupate/intervention-request/releases/tag/v6.0.0)`…&hotspot=0.25:0.75`hotspot + area[Crop an image](https://image.intervention.io/v3/modifying-images/resizing#crop-image) with a base area and a center point (relative to the area).
It needs `centerX`, `centerY`, `areaStartX`, `areaStartY`, `areaEndX`, `areaEndY` (all between 0 and 1).
[Since v7.0.0](https://github.com/ambroisemaupate/intervention-request/releases/tag/v7.0.0)`…&hotspot=0.25:0.75:0.1:0.1:0.9:0.9`### Fit position

[](#fit-position)

Due to URL rewriting, `align` filter can only takes one or two letters as a value. When no align filter is specified, `center` is used:

URL valueAlignment`tl`top-left`t`top`tr`top-right`l`left`c`center`r`right`bl`bottom-left`b`bottom`br`bottom-rightUsing standalone entry point
----------------------------

[](#using-standalone-entry-point)

An `index.php` file enables you to use this tool as a standalone app. You can adjust your configuration to set your native images folder or enable/disable cache.

Setup it on your webserver root, in a `intervention-request` folder and call this url (for example using MAMP/LAMP on your computer with included test images): `http://localhost:8888/intervention-request/?image=images/testPNG.png&fit=100x100`

Using as a library inside your projects
---------------------------------------

[](#using-as-a-library-inside-your-projects)

`InterventionRequest` class works seamlessly with *Symfony* `Request` and `Response`. It’s very easy to integrate it in your *Symfony* controller scheme:

```
use AM\InterventionRequest\Configuration;
use AM\InterventionRequest\InterventionRequest;
use AM\InterventionRequest\LocalFileResolver;
use Monolog\Logger;

/*
 * A test configuration
 */
$conf = new Configuration();
$conf->setCachePath(APP_ROOT.'/cache');
$conf->setImagesPath(APP_ROOT.'/files');
// Comment this line if jpegoptim is not available on your server
$conf->setJpegoptimPath('/usr/local/bin/jpegoptim');
// Comment this line if pngquant is not available on your server
$conf->setPngquantPath('/usr/local/bin/pngquant');

$fileResolver = new LocalFileResolver($conf->getImagesPath());

/*
 * InterventionRequest constructor asks 2 objects:
 *
 * - AM\InterventionRequest\Configuration
 * - AM\InterventionRequest\FileResolverInterface
 */
$intRequest = new InterventionRequest($conf, $fileResolver, new Logger('InterventionRequest'));
// Handle request and process image
$intRequest->handleRequest($request);

// getResponse returns a Symfony\Component\HttpFoundation\Response object
// with image mime-type and data. All you need is to send it!
return $intRequest->getResponse($request);
```

Use URL rewriting
-----------------

[](#use-url-rewriting)

If you want to use clean URL. You can add `ShortUrlExpander` class to listen to shorten URL like: `http://localhost:8888/intervention-request/f100x100-g/images/testPNG.png`.

First, add an `.htaccess` file (or its *Nginx* equivalent) to activate rewriting:

```
# .htaccess
# Pretty URLs

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [S=40]
RewriteRule . index.php [L]

```

Then add these lines to your application before handling `InterventionRequest`. `ShortUrlExpander` will work on your existing `$request` object.

```
use AM\InterventionRequest\ShortUrlExpander;
/*
 * Handle short url with Url rewriting
 */
$expander = new ShortUrlExpander($request);
// Enables using /cache in request path to mimic a pass-through file serve.
//$expander->setIgnorePath('/cache');
$params = $expander->parsePathInfo();
if (null !== $params) {
    // this will convert rewritten path to request with query params
    $expander->injectParamsToRequest($params['queryString'], $params['filename']);
}
```

### Shortcuts

[](#shortcuts)

URL shortcuts can be combined using `-` (dash) character. For example `f100x100-q50-g1-p0` stands for `fit=100x100&quality=50&greyscale=1&progressive=0`.

Query attributeShortcut letteralignafitfflipmcropcwidthwheighthbackgroundbgreyscalegblurlqualityqprogressivepinterlaceisharpenscontrast *(only from 0 to 100)*kno\_process *(do not process and load image in memory, allows optimizers)*nhotspotdUse pass-through cache
----------------------

[](#use-pass-through-cache)

Intervention request can save your images in a public folder to let *Apache* or *Nginx* serve them once they’ve been generated. This can reduce *time-to-first-byte* as PHP is not called any more.

- Make sure you have configured *Apache* or *Nginx* to serve real files **before** proxying your request to PHP. Otherwise this could lead to file overwriting!
- Pass-through cache is only available if you are using `ShortUrlExpander` to mimic a real image path without any query-string.
- Your cache folder **must** be public (in your document root), so your documents will be visible to anyone. If your images must be protected behind a PHP firewall, you should not activate *pass-through* cache.
- **Garbage collector won’t be called** because cached image won’t be served by your PHP server anymore but *Apache* or *Nginx*
- Pass-through cache will save image for the first time at the real path used in your request, make sure it won’t overwrite any application file.

Define your configuration cache path to a public folder:

```
$conf = new Configuration();
$conf->setCachePath(APP_ROOT . '/cache');
$conf->setUsePassThroughCache(true);
```

Then enable the `ShortUrlExpander` and **ignore your cache path** to process only path info after it.

```
$expander = new ShortUrlExpander($request);
// Enables using /cache in request path to mimic a pass-through file serve.
$expander->setIgnorePath('/cache');
```

Convert to webp
---------------

[](#convert-to-webp)

**Make sure your PHP is compiled with WebP image format.**

Intervention Request can automatically generated webp images by appending `.webp` to an existing image file.

Use `/image.jpg.webp` for `/image.jpg` file.

Intervention Request will look for a image file without `.webp` extension and throw a 404 error if it does not exist.

Force garbage collection
------------------------

[](#force-garbage-collection)

### Using command-line

[](#using-command-line)

```
bin/intervention gc:launch /path/to/my/cache/folder --log /path/to/my/log/file.log
```

Extend Intervention Request
---------------------------

[](#extend-intervention-request)

Intervention Request uses *Processors* to alter original images. By default, each available operation is handled by one `AbstractProcessor` inheriting class (look at the `src/Processor` folder).

You can create your own *Processors* and override default ones by injecting an array to your `InterventionRequest` object.

```
/*
 * Handle main image request with a
 * custom list of Processors.
 */
$iRequest = new InterventionRequest(
    $conf,
    $fileResolver,
    $log,
    [
        new Processor\WidenProcessor(),
        // add or replace with your own Processors
    ],
    $debug
);
```

Be careful, *Processors* position in this array is very important, please look at the default one in `InterventionRequest.php` class. Resizing processors should be the first, and quality processors should be the last as image operations will be done following your processors ordering.

### Add custom event subscribers

[](#add-custom-event-subscribers)

You can create custom actions if you need to optimize/alter your images before they get served using `ImageSavedEvent` and *Symfony* event system :

Create a class implementing `ImageEventSubscriberInterface` and, for example, listen to `ImageSavedEvent::NAME`

```
public static function getSubscribedEvents()
{
    return [
        ImageSavedEvent::class => 'onImageSaved',
    ];
}
```

This event will carry a `ImageSavedEvent` object with all you need to optimize/alter it. Then, use `$interventionRequest->addSubscriber($yourSubscriber)` method to register it.

#### Available events

[](#available-events)

Event nameDescription`RequestEvent::class`Main request handling event which handles `quality` and image processing and caching.`ImageBeforeProcessEvent::class`Before `Image` is being processed.`ImageAfterProcessEvent::class`After `Image` has been processed.`ImageSavedEvent::class`After `Image` has been saved to filesystem with a physical file-path. **This event is only dispatched if *caching* is enabled.**`ResponseEvent::class`After Symfony’s response has been built with image data. (Useful to alter headers)#### Listener examples

[](#listener-examples)

- `WatermarkListener` will print text on your image
- `KrakenListener` will optimize your image file using *kraken.io* external service
- `TinifyListener` will optimize your image file using *tinyjpg.com* external service
- `JpegTranListener` will optimize your image file using local `jpegtran` binary

Of course, you can build your own listeners and share them with us!

Performances
------------

[](#performances)

If your *Intervention-request* throws errors like that one:

```
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 5184 bytes).

```

It’s because you are trying to process a too large image. The solution is too increase your `memory_limit`PHP setting over `256M`. You can edit this file in your server `php.ini` file.

You can use `ini_set('memory_limit', '256M');` in your `index.php` file if your hosting plan allows you to dynamically change PHP configuration.

In general, we encourage to always downscale your native images before using them with *Intervention-request*. Raw jpeg images coming from your DSLR camera will give your PHP server a very hard time to process.

Optimization
------------

[](#optimization)

### jpegoptim

[](#jpegoptim)

If you have `jpegoptim` installed on your server, you can add it to your configuration

```
$conf->setJpegoptimPath('/usr/local/bin/jpegoptim');
```

### pngquant

[](#pngquant)

If you have `pngquant` installed on your server, you can add it to your configuration

```
$conf->setPngquantPath('/usr/local/bin/pngquant');
$conf->setLossyPng(true); // use palette lossy png compression - default: false
```

### oxipng

[](#oxipng)

If you have [`oxipng`](https://github.com/shssoichiro/oxipng) installed on your server, you can add it to your configuration

```
$conf->setOxipngPath('/usr/local/bin/oxipng');
```

### pingo

[](#pingo)

If you have [`pingo`](https://css-ig.net/pingo) installed on your server and `Wine`, you can add it to your configuration

```
$conf->setPingoPath('/usr/local/bin/pingo.exe');
$conf->setLossyPng(true); // use palette lossy png compression - default: false
$conf->setNoAlphaPingo(true); // Remove png transparency to compress more - default: false
```

### kraken.io

[](#krakenio)

If you have subscribed to a paid [kraken.io](https://kraken.io) plan, you can add the dedicated `KrakenListener` to send your resized images over the external service.

```
$iRequest->addSubscriber(new \AM\InterventionRequest\Listener\KrakenListener(
    'your-api-key',
    'your-api-secret',
    true,
    $log
));
```

Pay attention, that images will be sent over *kraken.io* API, it will take some additional time.

### tinyjpg.com

[](#tinyjpgcom)

If you have subscribed to a paid [tinyjpg.com](https://tinyjpg.com) plan, you can add the dedicated `TinifyListener` to send your resized images over the external service.

```
$iRequest->addSubscriber(new \AM\InterventionRequest\Listener\TinifyListener(
    'your-api-key',
    $log
));
```

Pay attention, that images will be sent over *kraken.io* API, it will take some additional time.

### jpegtran

[](#jpegtran)

If you want to use your system `jpegtran` or the *Mozjpeg* one, you can use the `JpegTranListener`.

```
$iRequest->addSubscriber(new \AM\InterventionRequest\Listener\JpegTranListener(
    '/usr/local/opt/mozjpeg/bin/jpegtran',
    $log
));
```

### Optimization benchmark

[](#optimization-benchmark)

With default quality to 90%.
AVIF conversion only supports custom compiled *ImageMagick* and only support lossless encoding.

UrlPHP raw*tinyjpg.com**Kraken.io* + lossyjpegoptimmozjpeg (jpegtran)WebP (90%)WebP (85%)AVIF (100%)/test/images/testUHD.jpg?width=2300405 kB168 kB187 kB395 kB390 kB235 kB155 kB94 kB/test/images/testUHD.jpg?width=1920294 kB132 kB134 kB285 kB282 kB176 kB115 kB71 kB/test/images/rhino.jpg?width=1920642 kB278 kB534 kB598 kB596 kB564 kB429 kB398 kB/test/images/rhino.jpg?width=1280325 kB203 kB278 kB303 kB301 kB295 kB229 kB227 kBUrlPHP rawpngquantoxipng*Kraken.io* + lossyWebP (100%)WebP (85%)AVIF (100%)/test/images/testPNG.png292 kB167 kB288 kB142 kB186 kB28 kB11.7 kBTesting
-------

[](#testing)

This project uses Docker for development environment. Copy `compose.override.yml` to `compose.override.yml`, use `php-dev` target and declare a volume on your project root folder.

```
services:
    intervention:
        build:
            context: .
            target: php-dev
        volumes:
            - ./:/app
        ports:
            -   "8080:80/tcp"
```

```
docker compose build
docker compose up
```

Then open `http://0.0.0.0:8080/assets/w300/rhino.jpg` in your browser. You should be able to test *intervention-request* with Passthrough cache and *ShortUrl* enabled. Set `IR_USE_PASSTHROUGH_CACHE=0` if you don't want cache to be served by *Nginx*.

### Disable cache during development

[](#disable-cache-during-development)

Set these variables to avoid caching images during development:

```
IR_DEBUG: 1
IR_USE_PASSTHROUGH_CACHE: 0
IR_GC_PROBABILITY: 1
IR_GC_TTL: 0
```

### Test grid

[](#test-grid)

A simple test grid is available at `http://localhost:8080/test.html`

### Unit tests

[](#unit-tests)

Make sure PHPUnit is properly configured and all required image processing dependencies are installed (such as GD, Imagick, or any relevant libraries your application uses).

This project includes a comprehensive set of unit tests to validate various image manipulation operations. These tests ensure that image transformations are applied correctly and consistently.

Available Tests :

- testFitImageGeneration: Verifies that the image is resized to fit within the given dimensions while maintaining its aspect ratio.
- testCropImageGeneration: Validates cropping of an image to the specified size.
- testCropResizedImageGeneration: Validates cropping of an image with a specific ratio and alignment to the specified size.
- testBackgroundImageGeneration: Tests the application or modification of a background color or image.
- testBlurImageGeneration: Checks the application of a blur effect to the image.
- testContrastImageGeneration: Validates the adjustment of image contrast.
- testFlipImageGeneration: Verifies image flipping (horizontal and vertical).
- testHotspotImageGeneration: Ensures correct placement and rendering of a focal point ("hotspot") on the image.
- testRotateImageGeneration: Checks that the image is rotated by the correct angle.
- testSharpenImageGeneration: Verifies the application of a sharpening filter.
- testWidenImageGeneration: Tests image resizing that increases the width while preserving content.
- testHeightenImageGeneration: Tests image resizing that increases the height.

#### Test Strategy

[](#test-strategy)

Each image processing test validates the output by comparing the MD5 hash of the generated image with a known, expected hash. This ensures that the image transformation produces exact and reproducible results, pixel for pixel.

For each test, the following approach is used:

- Load a source image (e.g., rhino.webp).
- Apply a specific transformation using query parameters (e.g., fit=500x500).
- Use a dedicated processor (e.g., FitProcessor) to apply the transformation.
- Save the processed image temporarily in a local output directory.
- Compute the MD5 hash of the generated image file.
- Compare it with the expected hash using an assertion.

This method ensures that even minor unintended changes in image generation logic will be detected during test runs.

#### Running the Tests

[](#running-the-tests)

To run only the unit tests:

```
php -d "memory_limit=-1" vendor/bin/phpunit tests/Processor
```

OR

```
make test-unit
```

### Functional tests

[](#functional-tests)

This project includes a comprehensive set of unit tests to validate various image manipulation operations. These tests ensure that image transformations are applied correctly and consistently. Available Tests :

- **Fit Image Generation**: Validates that an image is resized proportionally to fit within specified dimensions.
- **Crop Image Generation**: Ensures correct cropping of an image to the desired size.
- **Crop and Resize Image Generation**: Checks cropping combined with specific ratio and alignment for accurate resizing.
- **Background Image Generation**: Tests the application or customization of a background (either color or another image).
- **Blur Effect Application**: Verifies proper application of a blur effect to an image.
- **Contrast Adjustment**: Validates that image contrast adjustments are rendered accurately.
- **Flip Operation**: Tests horizontal and vertical flipping of an image.
- **Hotspot Placement**: Ensures precise placement of a focal point or "hotspot" on the image.
- **Rotation**: Validates rotation transformations applied to an image.
- **Sharpening Filter**: Ensures consistent application of sharpen filters.
- **Widen Image Functionality**: Tests width increase transformations while maintaining image content.
- **Heighten Image Functionality**: Tests height increase transformations while retaining image quality and content.

#### Test Strategy

[](#test-strategy-1)

Each image manipulation strategy is tested via HTTP-like requests using the `InterventionRequest` handler. This simulates real-world image transformations applied via URL parameters.

#### Running the Tests

[](#running-the-tests-1)

To run only the functional tests:

```
php -d "memory_limit=-1" vendor/bin/phpunit tests/Functional
```

OR

```
make test-functional
```

License
-------

[](#license)

*Intervention Request* is handcrafted by *Ambroise Maupate* under **MIT license**.

Have fun!

###  Health Score

55

—

FairBetter than 98% of packages

Maintenance55

Moderate activity, may be stable

Popularity40

Moderate usage in the ecosystem

Community20

Small or concentrated contributor base

Maturity89

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 97.6% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~68 days

Recently: every ~5 days

Total

55

Last Release

299d ago

Major Versions

v2.4.0 → v3.0.02020-05-26

v3.3.4 → v4.0.02023-02-10

v4.1.1 → v5.0.02025-02-27

v5.1.0 → v6.0.02025-05-27

v6.0.3 → v7.0.02025-07-23

PHP version history (7 changes)2.1.0PHP &gt;=5.6.0

v2.4.0PHP ^7.1.3

v3.1.0PHP ^7.1 || ^8.0

v3.2.0PHP ^7.2.5 || ^8.0

v3.3.0PHP ^7.4 || &gt;=8.0

v4.0.0PHP &gt;=8.0

v5.0.0PHP &gt;=8.2

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/380026?v=4)[Ambroise Maupate](/maintainers/ambroisemaupate)[@ambroisemaupate](https://github.com/ambroisemaupate)

---

Top Contributors

[![ambroisemaupate](https://avatars.githubusercontent.com/u/380026?v=4)](https://github.com/ambroisemaupate "ambroisemaupate (280 commits)")[![indual-emanuel](https://avatars.githubusercontent.com/u/129151312?v=4)](https://github.com/indual-emanuel "indual-emanuel (4 commits)")[![eliot488995568](https://avatars.githubusercontent.com/u/72140926?v=4)](https://github.com/eliot488995568 "eliot488995568 (2 commits)")[![designosis](https://avatars.githubusercontent.com/u/146623?v=4)](https://github.com/designosis "designosis (1 commits)")

---

Tags

gdimage-interventionimage-manipulationimage-processingimagemagickintervention-requesturlphpimage manipulationresizing

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/ambroisemaupate-intervention-request/health.svg)

```
[![Health](https://phpackages.com/badges/ambroisemaupate-intervention-request/health.svg)](https://phpackages.com/packages/ambroisemaupate-intervention-request)
```

###  Alternatives

[shopware/platform

The Shopware e-commerce core

3.3k1.5M3](/packages/shopware-platform)[laravel/framework

The Laravel Framework.

34.7k509.9M17.0k](/packages/laravel-framework)[prestashop/prestashop

PrestaShop is an Open Source e-commerce platform, committed to providing the best shopping cart experience for both merchants and customers.

9.0k15.4k](/packages/prestashop-prestashop)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

595.2M386](/packages/shopware-core)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.3M152](/packages/sulu-sulu)[contao/core-bundle

Contao Open Source CMS

1231.6M2.4k](/packages/contao-core-bundle)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
