PHPackages                             liip/cache-control-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. [HTTP &amp; Networking](/categories/http)
4. /
5. liip/cache-control-bundle

Abandoned → [friendsofsymfony/http-cache-bundle](/?search=friendsofsymfony%2Fhttp-cache-bundle)ArchivedSymfony-bundle[HTTP &amp; Networking](/categories/http)

liip/cache-control-bundle
=========================

This Bundle provides a way to set path based cache expiration headers via the app configuration and provides a helper to control the reverse proxy varnish.

1.0.7(12y ago)105125.6k241MITPHPPHP &gt;=5.3.2

Since Jul 26Pushed 8y ago63 watchersCompare

[ Source](https://github.com/liip/LiipCacheControlBundle)[ Packagist](https://packagist.org/packages/liip/cache-control-bundle)[ RSS](/packages/liip-cache-control-bundle/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (4)Dependencies (1)Versions (9)Used By (1)

UNMAINTAINED
============

[](#unmaintained)

This bundle is no longer maintained. Feel free to fork it if needed.

CacheControlBundle
==================

[](#cachecontrolbundle)

This Bundle provides a way to set path based cache expiration headers via the app configuration and provides a helper to control the reverse proxy varnish.

[![Build Status](https://camo.githubusercontent.com/a865809e4d3a6fbc27bac5ae2548ebfdb2a643380ce3ec32fc387a6ea4d1b348/68747470733a2f2f7365637572652e7472617669732d63692e6f72672f6c6969702f4c6969704361636865436f6e74726f6c42756e646c652e706e67)](http://travis-ci.org/liip/LiipCacheControlBundle)

This Bundle is Deprecated!
==========================

[](#this-bundle-is-deprecated)

The LiipCacheControlBundle went into maintenance only mode. It is replaced by the [FOSHttpCacheBundle](https://github.com/FriendsOfSymfony/FOSHttpCacheBundle).

See our [migration guide](MIGRATE_FOS.md) for help how to transition to the new bundle.

This repository will stay available to not break existing installations, but there will only be minimal maintenance at most.

Installation with composer
==========================

[](#installation-with-composer)

Just add the following line to your projects composer.json require section:

```
"liip/cache-control-bundle": "~1.0"

```

Enable the module
=================

[](#enable-the-module)

Add this bundle to your application's kernel:

```
// application/ApplicationKernel.php
public function registerBundles()
{
  return array(
      // ...
      new Liip\CacheControlBundle\LiipCacheControlBundle(),
      // ...
  );
}
```

Cache control
=============

[](#cache-control)

Simply configure as many paths as needed with the given cache control rules:

```
# app/config.yml
liip_cache_control:
    rules:
        # the controls section values are used in a call to Response::setCache();
        - { path: ^/, controls: { public: true, max_age: 15, s_maxage: 30, last_modified: "-1 hour" }, vary: [Accept-Encoding, Accept-Language] }

        # only match login.example.com
        - { host: ^login.example.com$, controls: { public: false, max_age: 0, s_maxage: 0, last_modified: "-1 hour" }, vary: [Accept-Encoding, Accept-Language] }

        # match a specific controller action
        - { controller: ^AcmeBundle:Default:index$, controls: { public: true, max_age: 15, s_maxage: 30, last_modified: "-1 hour" }, vary: [Accept-Encoding, Accept-Language] }
```

The matches are tried from top to bottom, the first match is taken and applied.

Run `app/console config:dump-reference liip_cache_control` to get the full list of configuration options.

About the path parameter
------------------------

[](#about-the-path-parameter)

The `path`, `host` and `controller` parameter of the rules represent a regular expression that a page must match to use the rule.

For this reason, and it's probably not the behaviour you'd have expected, the path `^/` will match any page.

If you just want to match the homepage you need to use the path `^/$`.

To match pages URLs with caching rules, this bundle uses the class `Symfony\Component\HttpFoundation\RequestMatcher`.

The `unless_role` makes it possible to skip rules based on if the current authenticated user has been granted the provided role.

Debug information
-----------------

[](#debug-information)

The debug parameter adds a `X-Cache-Debug` header to each response that you can use in your Varnish configuration.

```
# app/config.yml
liip_cache_control:
    debug: true
```

Add the following code to your Varnish configuration to have debug headers added to the response if it is enabled:

```
#in sub vcl_deliver
# debug info
# https://www.varnish-cache.org/trac/wiki/VCLExampleHitMissHeader
if (resp.http.X-Cache-Debug) {
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
        set resp.http.X-Cache-Hits = obj.hits;
    } else {
       set resp.http.X-Cache = "MISS";
    }
    set resp.http.X-Cache-Expires = resp.http.Expires;
} else {
    # remove Varnish/proxy header
    remove resp.http.X-Varnish;
    remove resp.http.Via;
    remove resp.http.X-Purge-URL;
    remove resp.http.X-Purge-Host;
}

```

Custom Varnish Parameters
-------------------------

[](#custom-varnish-parameters)

Additionally to the default supported headers, you may want to set custom caching headers for varnish.

```
# app/config.yml
liip_cache_control:
    rules:
        # the controls section values are used in a call to Response::setCache();
        - { path: /, controls: { stale_while_revalidate=9000, stale_if_error=3000, must-revalidate=false, proxy_revalidate=true } }
```

Custom Varnish Time-Outs
------------------------

[](#custom-varnish-time-outs)

Varnish checks the `Cache-Control` header of your response to set the TTL. Sometimes you may want that varnish should cache your response for a longer time than the browser. This way you can increase the performance by reducing requests to the backend.

To achieve this you can set the `reverse_proxy_ttl` option for your rule:

```
# app/config.yml
liip_cache_control:
    rules:
        # the controls section values are used in a call to Response::setCache();
        - { path: /, reverse_proxy_ttl: 300, controls: { public: true, max_age: 15, s_maxage: 30, last_modified: "-1 hour" } }
```

This example will add the header `X-Reverse-Proxy-TTL: 300` to your response.

But by default, varnish will not know anything about it. To get it to work you have to extend your varnish `vcl_fetch` configuration:

```
sub vcl_fetch {

    /* ... */

    if (beresp.http.X-Reverse-Proxy-TTL) {
        C{
            char *ttl;
            ttl = VRT_GetHdr(sp, HDR_BERESP, "\024X-Reverse-Proxy-TTL:");
            VRT_l_beresp_ttl(sp, atoi(ttl));
        }C
        unset beresp.http.X-Reverse-Proxy-TTL;
    }

    /* ... */

}

```

Varnish will then look for the `X-Reverse-Proxy-TTL` header and if it exists, varnish will use the found value as TTL and then remove the header. There is a beresp.ttl field in VCL but unfortunately it can only be set to absolute values and not dynamically. Thus we have to use a C code fragment.

Note that if you are using this, you should have a good purging strategy.

Varnish helper
==============

[](#varnish-helper)

This helper can be used to talk back to varnish to invalidate cached URLs. Configure the location of the varnish reverse proxies (be sure not to forget any, as each varnish must be notified separately):

```
# app/config.yml
liip_cache_control:
    varnish:
        host: http://www.liip.ch
        ips: 10.0.0.10, 10.0.0.11
        port: 80
        headers: ["Authorization: Basic Zm9vOmJhcg==", "X-Another-Header: here"]
```

- **host**: This must match the web host clients are using when connecting to varnish. You will not notice if this is mistyped, but cache invalidation will never happen. You can also add a regexp here like ".*" to clear all host entries. The regexp will be surrounded by "^(" and ")$" ending in "^(.*)$" in this example.
- **ips**: List of IP adresses of your varnish servers. Comma separated.
- **port**: The port varnish is listening on for incoming web connections.
- **headers**: (optional) If you want to send special headers with each request sent to varnish, you can add them here (as array)

To use the varnish cache helper you must inject the `liip_cache_control.varnish` service or fetch it from the service container:

```
// using a "manual" url
$varnish = $this->container->get('liip_cache_control.varnish');
/* $response Is an associative array with keys 'headers', 'body', 'error' and 'errorNumber' for each configured IP.
   A sample response will look like:
   array('10.0.0.10' => array('body'    => 'raw-request-body',
                              'headers' => 'raw-headers',
                              'error'   =>  'curl-error-msg',
                              'errorNumber'   =>  integer-curl-error-number),
          '10.0.0.11' => ...)
*/
$response = $varnish->invalidatePath('/some/path');

// using the router to generate the url
$router = $this->container->get('router');
$varnish = $this->container->get('liip_cache_control.varnish');
$response = $varnish->invalidatePath($router->generate('myRouteName'));
```

When using ESI, you will want to purge individual fragments. To generate the corresponding `_internal` route, inject the `http_kernel` into your controller and use HttpKernel::generateInternalUri with the parameters as in the twig `render` tag.

Purging
-------

[](#purging)

Add the following code to your Varnish configuration to have it handle PURGE requests (make sure to uncomment the appropiate line(s))

varnish 3.x

```
#top level:
# who is allowed to purge from cache
# https://www.varnish-cache.org/docs/trunk/users-guide/purging.html
acl purge {
    "127.0.0.1"; #localhost for dev purposes
    "10.0.11.0"/24; #server closed network
}

#in sub vcl_recv
# purge if client is in correct ip range
if (req.request == "PURGE") {
    if (!client.ip ~ purge) {
        error 405 "Not allowed.";
    }

    return(lookup);
}

sub vcl_hit {
  if (req.request == "PURGE") {
     purge;
     error 200 "Purged";
     return (error);
  }
}

sub vcl_miss {
   if (req.request == "PURGE") {
     purge;
     error 404 "Not in cache";
     return (error);
   }
}

```

In Varnish 2, the `purge` action is actually just marking caches as invalid. This is called `ban` in Varnish 3.

Varnish 2.x

```
#top level:
# who is allowed to purge from cache
# https://www.varnish-cache.org/docs/trunk/users-guide/purging.html
acl purge {
    "127.0.0.1"; #localhost for dev purposes
    "10.0.11.0"/24; #server closed network
}

#in sub vcl_recv
# purge if client is in correct ip range
if (req.request == "PURGE") {
    if (!client.ip ~ purge) {
        error 405 "Not allowed.";
    }

    purge("req.url ~ " req.url);
    purge("req.url ~ " req.url);
    error 200 "Success";
}

```

NOTE: this code invalidates the url for all domains. If your varnish serves multiple domains, you should improve this configuration.

The varnish path invalidation is about equivalent to doing this:

```
 netcat localhost 6081 get('liip_cache_control.varnish');
$varnish->refreshPath('/some/path');
```

Banning from the console
------------------------

[](#banning-from-the-console)

You can also ban URLs from the console

```
app/console liip:cache-control:varnish:invalidate
```

will ban (invalidate) all entries in your configured varnish servers (matching varnish.host)

```
app/console liip:cache-control:varnish:invalidate /posts.*
```

will ban (invalidate) all entries in your configured varnish servers, where the URL starts with "/posts". Any regular expression understood by varnish can be used here.

It uses the Varnish Helper class, therefore if you defined more than one varnish server in the config file (in varnish.ips), the entries will be deleted in all servers.

Cache authorization listener
============================

[](#cache-authorization-listener)

Enable the authorization listener:

```
# app/config.yml
liip_cache_control:
    authorization_listener: true
```

This listener makes it possible to stop a request with a 200 "OK" for HEAD requests right after the security firewall has finished. This is useful when one uses Varnish while handling content that is not available for all users.

In this scenario on a cache hit, Varnish can be configured to issue a HEAD request when this content is accessed. This way Symfony2 can be used to validate the authorization, but no work needs to be made to regenerate the content that is already in the Varnish cache.

Note this obviously means that it only works with path based Security. Any additional security implemented inside the Controller will be ignored.

Note further that a HEAD response is supposed to contain the same HTTP header meta data as the GET response to the same URL. However for the purpose of this use case we have no other choice but to assume a 200.

```
backend default {
    .host = “127.0.0.1″;
    .port = “81″;
}

acl purge {
    “127.0.0.1″; #localhost for dev purposes
}

sub vcl_recv {
    # pipe HEAD requests as we convert all GET requests to HEAD and back later on
    if (req.request == “HEAD”) {
        return (pipe);
    }

    if (req.request == "GET") {
        if (req.restarts == 0) {
            set req.request = "HEAD";
            return (pass);
        } else {
            set req.http.Surrogate-Capability = "abc=ESI/1.0";
            return (lookup);
        }
    }
}

sub vcl_hash {
}

sub vcl_fetch {
    if (beresp.http.Cache-Control ~ “(private|no-cache|no-store)”) {
        return (pass);
    }

    if (beresp.status >= 200 && beresp.status < 300) {
        if (req.request == "HEAD") {
            # if the BE response said OK, change the request type back to GET and restart
            set req.request = "GET";
            restart;
        }
    } else {
        # In any other case (authentication 302 most likely), just pass the response to the client
        # Don't forget to set the content-length, as the HEAD response doesn't have any (and the client will hang)
        if (req.request == "HEAD") {
            set beresp.http.content-length = "0";
        }

        return (pass);
    }

    if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
        unset beresp.http.Surrogate-Control;
        // varnish < 3.0:
        esi;
        // varnish 3.0 and later:
        // set beresp.do_esi = true;
    }
}

```

Flash message listener
======================

[](#flash-message-listener)

The Response flash message listener moves all flash messages currently set into a cookie. This way it becomes possible to better handle flash messages in combination with ESI. The ESI configuration will need to ignore the configured cookie. It will then be up to the client to read out the cookie, display the flash message and remove the flash message via javascript.

```
# app/config.yml
liip_cache_control:
    flash_message_listener:
        name: flashes
        path: /
        host: null
        secure: false
        httpOnly: true
```

If you do not want the flash message listener, you can disable it:

```
# app/config.yml
liip_cache_control:
    flash_message_listener:
        enabled: false
```

###  Health Score

42

—

FairBetter than 90% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity44

Moderate usage in the ecosystem

Community32

Small or concentrated contributor base

Maturity63

Established project with proven stability

 Bus Factor1

Top contributor holds 52.5% 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 ~72 days

Recently: every ~50 days

Total

8

Last Release

4533d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/76576?v=4)[David Buchmann](/maintainers/dbu)[@dbu](https://github.com/dbu)

![](https://avatars.githubusercontent.com/u/20873?v=4)[Luke Smith](/maintainers/lsmith)[@lsmith](https://github.com/lsmith)

---

Top Contributors

[![lsmith77](https://avatars.githubusercontent.com/u/300279?v=4)](https://github.com/lsmith77 "lsmith77 (63 commits)")[![dbu](https://avatars.githubusercontent.com/u/76576?v=4)](https://github.com/dbu "dbu (28 commits)")[![jnonon](https://avatars.githubusercontent.com/u/959315?v=4)](https://github.com/jnonon "jnonon (5 commits)")[![gimler](https://avatars.githubusercontent.com/u/200904?v=4)](https://github.com/gimler "gimler (4 commits)")[![digitalkaoz](https://avatars.githubusercontent.com/u/293591?v=4)](https://github.com/digitalkaoz "digitalkaoz (4 commits)")[![zlatio](https://avatars.githubusercontent.com/u/545553?v=4)](https://github.com/zlatio "zlatio (4 commits)")[![snc](https://avatars.githubusercontent.com/u/216730?v=4)](https://github.com/snc "snc (3 commits)")[![mguillermin](https://avatars.githubusercontent.com/u/252093?v=4)](https://github.com/mguillermin "mguillermin (2 commits)")[![krispypen](https://avatars.githubusercontent.com/u/156955?v=4)](https://github.com/krispypen "krispypen (2 commits)")[![nicam](https://avatars.githubusercontent.com/u/182071?v=4)](https://github.com/nicam "nicam (1 commits)")[![Nyholm](https://avatars.githubusercontent.com/u/1275206?v=4)](https://github.com/Nyholm "Nyholm (1 commits)")[![Seldaek](https://avatars.githubusercontent.com/u/183678?v=4)](https://github.com/Seldaek "Seldaek (1 commits)")[![nenadalm](https://avatars.githubusercontent.com/u/1227933?v=4)](https://github.com/nenadalm "nenadalm (1 commits)")[![chregu](https://avatars.githubusercontent.com/u/47106?v=4)](https://github.com/chregu "chregu (1 commits)")

---

Tags

bundlecachephpsymfonysymfony-bundlehttpcachingesivarnish

### Embed Badge

![Health badge](/badges/liip-cache-control-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/liip-cache-control-bundle/health.svg)](https://phpackages.com/packages/liip-cache-control-bundle)
```

###  Alternatives

[friendsofsymfony/http-cache-bundle

Set path based HTTP cache headers and send invalidation requests to your HTTP cache

43813.2M47](/packages/friendsofsymfony-http-cache-bundle)[friendsofsymfony/http-cache

Tools to manage HTTP caching proxies with PHP

36114.7M36](/packages/friendsofsymfony-http-cache)[sofascore/purgatory-bundle

A Symfony bundle for HTTP cache invalidation with support for various backends like Varnish.

11665.0k](/packages/sofascore-purgatory-bundle)[flowpack/varnish

Varnish integration for Neos

2052.9k](/packages/flowpack-varnish)

PHPackages © 2026

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