2017 © Pedro Peláez
 

symfony-bundle thumbnail-bundle

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

image

genj/thumbnail-bundle

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

  • Monday, October 9, 2017
  • by genj
  • Repository
  • 4 Watchers
  • 1 Stars
  • 4,518 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 3 Forks
  • 0 Open issues
  • 6 Versions
  • 1 % Grown

The README.md

GenjThumbnailBundle

Features:, (*1)

  • 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, (*2)

  • CDN using AWS-S3 (optional), (*3)

    • 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

  • VichUploaderBundle - https://packagist.org/packages/vich/uploader-bundle
  • LiipImagineBundle - https://packagist.org/packages/liip/imagine-bundle
  • LeagueFlysystem-aws-s3-v3 - https://packagist.org/packages/league/flysystem-aws-s3-v3 (for AWS-S3 only)
  • OneUpFlysystem - https://packagist.org/packages/oneup/flysystem-bundle (for AWS-S3 only)

Optional

  • GenjFrontendUrlBundle - https://github.com/genj/GenjFrontendUrlBundle

Installation

  • Add the bundle to your project composer.json, (*4)

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

    and run composer update, (*5)

  • Register VichUploaderBundle, LiipImagineBundle, FlySystemBundle and GenjThumbnailBundle in AppKernel.php:, (*6)

    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., (*7)

    domain: <SITE_DOMAIN.com>  # (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., (*8)

    cdn_domain: static.<SITE_DOMAIN.com>  # (.com is just an example)
    
  • Add this to app/config/config.yml:, (*9)

    imports:
        - { resource: thumbnailing.yml }
        - { resource: cdn.yml }
    
    framework:
        ...
        session:
            ...
            cookie_domain: "%domain%"
    
  • Create file app/config/thumbnailing.yml with this content:, (*10)

    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 https://github.com/liip/LiipImagineBundle/blob/1.0/README.md, (*11)

  • Add configuration, (*12)

    /app/config/config.yml, (*13)

    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., (*14)

    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., (*15)

  • enable route in routing.yml:, (*16)

    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:, (*17)

    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., (*18)

Usage

To generate an URL to a thumbnail:, (*19)

<img src="{{ genj_thumbnail(object, 'fileUpload', 'teaser'}) }}">

To grab image info (width and height):, (*20)

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

<img src="{{ genj_thumbnail(object, 'fileUpload', 'teaser'}) }}" width="{{ image_info.width }}" height="{{ image_info.height }}">

Notes

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

Setup AWS-S3 (optional)

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

  • If no bucket is available yet, create and configure one. See the section Create and configure a bucket on AWS-S3 below., (*23)

  • add additional external vendors in your composer.json, (*24)

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

    and run composer update, (*25)

  • update your app/config/config.yml for the CDN usage, (*26)

    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: <AWS_REGION>
                  credentials:
                      key: <AWS_KEY>
                      secret: <AWS_SECRET>
    
    oneup_flysystem:
        adapters:
            staticcdn_adapter:
                awss3v3:
                    client: aws.s3_client
                    bucket: <BUCKET_NAME>
                    prefix: ~
        filesystems:
            thumbnails:
                adapter: staticcdn_adapter
    
    

    Replace the following placeholders with the actual data:, (*27)

    <REGION> The `region` that the bucket was created in, for ex. `eu-west-1`
    <BUCKET_NAME> The name of the bucket to use.
    <AWS_KEY> The `access key` that AWS assigned to the bucket.
    <AWS_SECRET> 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., (*28)

  • Define a value for cdn_domain in parameters.yml and compose it as follows:, (*29)

    <BUCKET_NAME>.s3-website.<REGION>.amazonaws.com.
    

    for example:, (*30)

    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., (*31)

  • Modify routing to use %cdn_domain% instead of %domain%., (*32)

    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

  • Log into the AWS administation console at https://aws.amazon.com/console/, (*33)

  • Create a bucket., (*34)

    Use a name like static.<DOMAIN>.com that clearly defines the website that the bucket is used for. The thumbnail bundle will create directories inside this bucket as needed., (*35)

  • Set bucket policy, (*36)

    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 http://docs.aws.amazon.com/AmazonS3/latest/dev/s3-access-control.html, (*37)

    Replace <BUCKET_NAME> with the actual name of the bucket., (*38)

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "PublicReadForGetBucketObjects",
                "Effect": "Allow",
                "Principal": "*",
                "Action": "s3:GetObject",
                "Resource": "arn:aws:s3:::<BUCKET_NAME>/*" 
            }
        ]
    }
    
  • Enable website hosting (static hosting), (*39)

    http://docs.aws.amazon.com/AmazonS3/latest/dev/WebsiteHosting.html, (*40)

  • Upload an index.html and error.html (optional), (*41)

    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., (*42)

    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., (*43)

  • Set up the redirection rule., (*44)

    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., (*45)

    By convention this should take the form of upload.<DOMAIN>.com., (*46)

    <RoutingRules>
        <RoutingRule>
            <Condition>
                <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
            </Condition>
            <Redirect>
                <HostName>UPLOAD_DOMAIN</HostName>
                <HttpRedirectCode>302</HttpRedirectCode>
            </Redirect>
        </RoutingRule>
    </RoutingRules>
    

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., (*47)

  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), (*48)

  2. Deleting the image should make the image disappear from the S3 bucket. ¡, (*49)

  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., (*50)

  4. Images uploaded to the S3 bucket should be publicly available because of the defined policy., (*51)

  5. Accessing an image on S3 that does not exist should cause S3 to redirect back to the website., (*52)

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., (*53)

  • Add to your cdn.yml:, (*54)

    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: https://www.cloudflare.com/a/overview/, (*55)

  • auth_email and auth_key (called Global API Key on the website) can be found on your Profile page: https://www.cloudflare.com/a/profile, (*56)

  • Add the secrets to your parameters.yml:, (*57)

    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:, (*58)

    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:, (*59)

    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 https://www.cloudflare.com/a/page-rules/example.com. The rule should be Cache Level: Bypass., (*60)

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., (*61)

  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:, (*62)

    $ 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:, (*63)

    $ 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., (*64)

  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., (*65)

The Versions

09/10 2017

dev-master

9999999-dev http://github.com/genj/GenjThumbnailBundle

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

  Sources   Download

MIT

The Requires

 

by Choong Wei Tjeng
by Nico Kaag
by Susan Lau

php bundle symfony thumbnail symfony-bundle genj

07/11 2016

dev-vogue-thumbnail-info-patch

dev-vogue-thumbnail-info-patch http://github.com/genj/GenjThumbnailBundle

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

  Sources   Download

MIT

The Requires

 

by Choong Wei Tjeng
by Nico Kaag
by Susan Lau

symfony2 bundle thumbnail genj

24/12 2015

v1.0.1-patch1

1.0.1.0-patch1 http://github.com/genj/GenjThumbnailBundle

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

  Sources   Download

MIT

The Requires

 

by Choong Wei Tjeng
by Nico Kaag
by Susan Lau

symfony2 bundle thumbnail genj

21/12 2015

dev-redmine_7104

dev-redmine_7104 http://github.com/genj/GenjThumbnailBundle

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

  Sources   Download

MIT

The Requires

 

by Choong Wei Tjeng
by Nico Kaag
by Susan Lau

symfony2 bundle thumbnail genj

04/08 2015

v1.0.1

1.0.1.0 http://github.com/genj/GenjThumbnailBundle

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

  Sources   Download

MIT

The Requires

 

by Choong Wei Tjeng
by Nico Kaag
by Susan Lau

symfony2 bundle thumbnail genj

23/02 2015

v1.0.0

1.0.0.0 http://github.com/genj/GenjThumbnailBundle

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

  Sources   Download

MIT

The Requires

 

by Choong Wei Tjeng
by Nico Kaag
by Susan Lau

symfony2 bundle thumbnail genj