PHPackages                             genj/thumbnail-bundle - 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. genj/thumbnail-bundle

AbandonedArchivedSymfony-bundle[Image &amp; Media](/categories/media)

genj/thumbnail-bundle
=====================

Uses Liip/ImagineBundle and generates SEO-friendly thumbnail-names

v1.0.1-patch1(10y ago)04.7k5MITPHP

Since Feb 23Pushed 8y ago2 watchersCompare

[ Source](https://github.com/genj/GenjThumbnailBundle)[ Packagist](https://packagist.org/packages/genj/thumbnail-bundle)[ Docs](http://github.com/genj/GenjThumbnailBundle)[ RSS](/packages/genj-thumbnail-bundle/feed)WikiDiscussions master Synced 1w ago

READMEChangelog (3)Dependencies (4)Versions (4)Used By (0)

GenjThumbnailBundle
===================

[](#genjthumbnailbundle)

Features:

- On-request thumbnail generation
- Image is cached on disk - subsequent requests will serve the file directly from disk instead of hitting the framework
- Configurable thumbnail formats supported
- A thumbnail format can have multiple filters
- Filenames based on slug (SEO friendly)
- Images can be served over a separate subdomain e.g. for loadbalancing or S3 usage. Conventionally we use 'static', but any name is possible.
- Uploads and thumbnails are stored in subdirectories based on the object ID, to prevent too many files in 1 directory
- Can generate thumbnail of any object property or even static assets
- CDN using AWS-S3 (optional)

    - Thumbnails are copied on AWS-S3, browser fetches thumbnails from the S3 CDN.
    - A 404 on S3 will redirect the browser fall back to the webserver which will then create the file and upload it to S3.

Requirements
------------

[](#requirements)

- VichUploaderBundle -
- LiipImagineBundle -
- LeagueFlysystem-aws-s3-v3 -  (for AWS-S3 only)
- OneUpFlysystem -  (for AWS-S3 only)

### Optional

[](#optional)

- GenjFrontendUrlBundle -

Installation
============

[](#installation)

- Add the bundle to your project composer.json

    ```
    "require": {
    [..]
        "genj/thumbnail-bundle": "dev-master",
    [..]
    }

    ```

    and run `composer update`
- Register VichUploaderBundle, LiipImagineBundle, FlySystemBundle and GenjThumbnailBundle in AppKernel.php:

    ```
    new Vich\UploaderBundle\VichUploaderBundle(),
    new Liip\ImagineBundle\LiipImagineBundle(),
    new Genj\ThumbnailBundle\GenjThumbnailBundle(),
    new Oneup\FlysystemBundle\OneupFlysystemBundle(),

    ```
- Create a `domain` parameter in app/config/parameters.yml and fill it with the domain of the website without subdomain.

    ```
    domain:   # (without subdomain, .com is just an example)

    ```
- Create a `cdn_domain` parameter in app/config/parameters.yml and fill it with the domain from which you serve static assets. Can be the same as `domain`.

    ```
    cdn_domain: static.  # (.com is just an example)

    ```
- Add this to app/config/config.yml:

    ```
    imports:
        - { resource: thumbnailing.yml }
        - { resource: cdn.yml }

    framework:
        ...
        session:
            ...
            cookie_domain: "%domain%"

    ```
- Create file app/config/thumbnailing.yml with this content:

    ```
    liip_imagine:
        driver: imagick
        filter_sets:

            # used in admin and in listings
            teaser:
                quality: 90
                filters:
                    upscale: { min: [320, 320] }
                    thumbnail: { size: [320, 320] }
                    format: ['jpg']

            # main image - not over full size
            detail:
                quality: 90
                filters:
                    relative_resize: { widen: 1000 }
                    format: ['jpg']

            # full size
            big:
                quality: 90
                filters:
                    relative_resize: { widen: 1600 }
                    format: ['jpg']

    ```

    For more examples of what can be configured here, see the READ.ME of the liib imagine bundle at
- Add configuration

    /app/config/config.yml

    ```
    liip_imagine:
        resolvers:
            default:
                web_path: ~

        filter_sets:
            cache: ~

        loaders:
            default:
                filesystem:
                    data_root: '%data_root%'

    ```

    The `data_root` parameters should point to your document root.

    If you wish to use a CDN then complete this section and follow the instructions in the **setup AWS-S3** or **setup Cloudflare** section below.
- enable route in routing.yml:

    ```
    genj_thumbnail:
        path:  /thumbnails/{bundleName}/{entityName}/{attribute}/{filter}/{idShard}/{slug}-{id}.{_format}
        host: '%domain%'
        defaults:
            _controller: liip_imagine.controller:filterActionForObject
            subdomain: 'static'
            attribute: 'fileUpload'
        requirements:
            _format: jpg|jpeg|gif|png
            slug: "[a-zA-Z0-9\\-\\/]+"
            idShard: "[\\w/]+"
            id: "^\\d+$"

    ```

    OR if you don't feel the need to adjust the original routing:

    ```
    genj_thumbnail_bundle:
        resource: "@GenjThumbnailBundle/Resources/config/routing.yml"

    ```

    Note: if you want to use the CDN, the routing is different, see the **setup AWS-S3** or the **setup Cloudflare** section below.

Usage
=====

[](#usage)

To generate an URL to a thumbnail:

```

```

To grab image info (width and height):

```
{% set image_src  = genj_thumbnail(object, 'fileUpload', 'teaser'}) %}
{% set image_info = image_src|genj_thumbnail_info %}

```

Notes
=====

[](#notes)

Make sure you limit the length of your slug field, because browser url may be limited.

Setup AWS-S3 (optional)
=======================

[](#setup-aws-s3-optional)

*This is only required if the site will use S3 as a CDN to store thumbnails.*

- If no bucket is available yet, create and configure one. See the section **Create and configure a bucket on AWS-S3** below.
- add additional external vendors in your composer.json

    ```
    "require": {
    [..]
        "genj/thumbnail-bundle": "dev-master",
        "league/flysystem-aws-s3-v3": "^1.0",
        "oneup/flysystem-bundle": "^1.7",
    [..]
    }

    ```

    and run `composer update`
- update your app/config/config.yml for the CDN usage

    ```
    liip_imagine:
        cache: withCdn
        resolvers:
            default:
                web_path: ~
            withCdn:
                localAndCdnResolver:
                    use_cdn: true
                    cdn: oneup_flysystem.thumbnails_filesystem
        filter_sets:
            cache: ~
        loaders:
            default:
                filesystem:
                    data_root: '%data_root%'

    services:
        aws.s3_client:
            class: Aws\S3\S3Client
            arguments:
              aws_s3_client:
                  version: latest
                  region:
                  credentials:
                      key:
                      secret:

    oneup_flysystem:
        adapters:
            staticcdn_adapter:
                awss3v3:
                    client: aws.s3_client
                    bucket:
                    prefix: ~
        filesystems:
            thumbnails:
                adapter: staticcdn_adapter

    ```

    Replace the following placeholders with the actual data:

    ```
       The `region` that the bucket was created in, for ex. `eu-west-1`
       The name of the bucket to use.
       The `access key` that AWS assigned to the bucket.
       The `secret key` that AWS assigned to the bucket.

    ```

    The `%domain%` parameter does not have to be filled in, it is taken from `parameters.yml`.
- Define a value for `cdn_domain` in `parameters.yml` and compose it as follows:

    ```
    .s3-website..amazonaws.com.

    ```

    for example:

    ```
    cdn_domain: static.glamour.nl.s3-website.eu-west-1.amazonaws.com.

    ```

    Make sure that the bucket-name and region are identical to the content of your config.yml.
- Modify routing to use %cdn\_domain% instead of %domain%.

    ```
    genj_thumbnail:
        path:  /thumbnails/{bundleName}/{entityName}/{attribute}/{filter}/{idShard}/{slug}-{id}.{_format}
        host: '{domain}'
        defaults:
            _controller: liip_imagine.controller:filterActionForObject
            subdomain: 'static'
            domain: '%cdn_domain%'
            attribute: 'fileUpload'
        requirements:
            _format: jpg|jpeg|gif|png
            slug: "[a-zA-Z0-9\\-\\/]+"
            idShard: "[\\w/]+"
            id: "^\\d+$"
            domain: ".*"

    ```

Create and configure a bucket on AWS-S3
---------------------------------------

[](#create-and-configure-a-bucket-on-aws-s3)

- Log into the AWS administation console at
- Create a bucket.

    Use a name like `static..com` that clearly defines the website that the bucket is used for. The thumbnail bundle will create directories inside this bucket as needed.
- Set bucket policy

    Instruct S3 to allow anonymous read-only access to the objects in the bucket. For more information about how to set this up, see the S3 documentation at

    Replace `` with the actual name of the bucket.

    ```
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "PublicReadForGetBucketObjects",
                "Effect": "Allow",
                "Principal": "*",
                "Action": "s3:GetObject",
                "Resource": "arn:aws:s3:::/*"
            }
        ]
    }

    ```
- Enable website hosting (static hosting)

- Upload an index.html and error.html (optional)

    These pages are displayed when users navigate to a folder instead of an image (index.html) and when there was an error accessing the requested object (error.html) Users should never see these files but it is good practice to put a userfriendly (branded) message there, explaining what has happened and why they are not seeing what the where expecting.

    If you upload these documents, make sure to place them in the root of the bucket, make them readable by `everyone`, and put their filenames in the static hosting section of bucket configuration.
- Set up the redirection rule.

    When S3 cannot find the requested image, this rule will redirect the browser to the webserver which will then serve the image and upload it to S3 so the next user will not get a 404 anymore. Don't forget to fill in the correct value for `Hostname`, replace `UPLOAD_DOMAIN` with the actual name of hte host that supplies the images.

    By convention this should take the form of `upload..com`.

    ```

                404

                UPLOAD_DOMAIN
                302

    ```

Testing the AWS-S3 CDN
----------------------

[](#testing-the-aws-s3-cdn)

To test if the setup is working, you should do the following with an image that is accessed by the website using the twig thumbnail filter.

1. After uploading an image in the website and seeing it appear on the site, that image path should be available in the AWS-S3 bucket aswell. (images are not uploaded to S3 until they are requested from the site)
2. Deleting the image should make the image disappear from the S3 bucket. ¡
3. Uploading a new image over an existing image should delete the old image on S3, after which requesting it from the site should add a copy of the new image.
4. Images uploaded to the S3 bucket should be publicly available because of the defined policy.
5. Accessing an image on S3 that does not exist should cause S3 to redirect back to the website.

Setup Cloudflare (optional)
===========================

[](#setup-cloudflare-optional)

The bundle supports the purging of thumbnails from Cloudflare CDN. This is handled by the `CloudflarePurger` and is disabled by default. The `CloudflarePurger` also listens for the VichUploaderBundle event `vich_uploader.pre_remove`and will purge the original uploaded file too. To enable it, do the following.

- Add to your `cdn.yml`:

    ```
    genj_thumbnail:
        cloudflare:
            enable:     true
            zone_id:    '%genj_thumbnail.cloudflare.zone_id%'
            auth_email: '%genj_thumbnail.cloudflare.auth_email%'
            auth_key:   '%genj_thumbnail.cloudflare.auth_key%'

    ```
- `zone_id` can be found on your domain overview page: &lt;your\_domain&gt;
- `auth_email` and `auth_key` (called `Global API Key` on the website) can be found on your Profile page:
- Add the secrets to your `parameters.yml`:

    ```
    genj_thumbnail.cloudflare.zone_id:
    genj_thumbnail.cloudflare.auth_email:
    genj_thumbnail.cloudflare.auth_key:

    ```
- If you host the thumbnails on a separate domain, configure the routing as such:

    ```
    genj_thumbnail:
        path:  /thumbnails/{bundleName}/{entityName}/{attribute}/{filter}/{idShard}/{slug}-{id}.{_format}
        host: '{domain}'
        defaults:
            _controller: liip_imagine.controller:filterActionForObject
            domain: '%cdn_domain%'
            attribute: 'fileUpload'
        requirements:
            _format: jpg|jpeg|gif|png
            slug: "[a-zA-Z0-9\\-\\/]+"
            idShard: "[\\w/]+"
            id: "^\\d+$"
            domain: ".*"

    ```
- And add the corresponding `cdn_domain` in your parameters.yml:

    ```
    cdn_domain: static.example.com

    ```
- If you want to exclude things from the Cloudflare cache (e.g. your `app_dev.php`), you can add those under Page Rules in your Cloudflare control panel. See &lt;example.com&gt;. The rule should be `Cache Level: Bypass`.

Testing Cloudflare CDN
----------------------

[](#testing-cloudflare-cdn)

To test if the setup is working, you should do the following with an image that is accessed by the website using the twig thumbnail filter. Note that there can be a few seconds of delay because of the way information is distributed amongst the Cloudflare nodes.

1. After uploading an image in the website and seeing it appear on the site, hitting it with curl should give `CF-Cache-Status: HIT`:

    ```
    $ curl -I https://example.com/thumbnail.jpg

    HTTP/1.1 200 OK
    ...
    CF-Cache-Status: HIT

    ```
2. Deleting the image should purge the thumbnail from Cloudflare caches. The next hit with curl should give `CF-Cache-Status: MISS`:

    ```
    $ curl -I https://example.com/thumbnail.jpg

    HTTP/1.1 200 OK
    ...
    CF-Cache-Status: MISS

    ```
3. Uploading a new image over an existing image should purge the thumbnail from Cloudflare caches, so a subsequent curl hit should result in `CF-Cache-Status: MISS`. This will cache the thumbnail, so the curl hit after that should give `CF-Cache-Status: HIT`.
4. Accessing a thumbnail on Cloudflare that does not exist, should show the website's 404 page and *not* cache it. So repeatedly requesting a non-existing should keep giving `CF-Cache-Status: MISS`.

###  Health Score

33

—

LowBetter than 75% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity20

Limited adoption so far

Community15

Small or concentrated contributor base

Maturity65

Established project with proven stability

 Bus Factor1

Top contributor holds 50% 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 ~152 days

Total

3

Last Release

3798d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/9d57ed47401a1ad476effd86580ad6a595cc480778030c7bce19d7536879104a?d=identicon)[genj](/maintainers/genj)

---

Top Contributors

[![choonge](https://avatars.githubusercontent.com/u/334814?v=4)](https://github.com/choonge "choonge (26 commits)")[![maartendekeizer](https://avatars.githubusercontent.com/u/1061334?v=4)](https://github.com/maartendekeizer "maartendekeizer (10 commits)")[![slaubi](https://avatars.githubusercontent.com/u/332298?v=4)](https://github.com/slaubi "slaubi (10 commits)")[![nicokaag](https://avatars.githubusercontent.com/u/2652304?v=4)](https://github.com/nicokaag "nicokaag (6 commits)")

---

Tags

bundlethumbnailSymfony2genj

### Embed Badge

![Health badge](/badges/genj-thumbnail-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/genj-thumbnail-bundle/health.svg)](https://phpackages.com/packages/genj-thumbnail-bundle)
```

###  Alternatives

[mediamonks/sonata-media-bundle

A powerful, flexible and easy to use alternative for the existing Sonata Media Bundle

109.8k](/packages/mediamonks-sonata-media-bundle)[symfonyid/admin-bundle

Provide Admin Generator with KISS Principle

141.6k](/packages/symfonyid-admin-bundle)

PHPackages © 2026

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