alengo/sulu-http-cache-bundle
Integrates HTTP caching with Sulu CMS to speed up sites and reduce backend load by caching responses at the HTTP layer. Configure cache behavior for Sulu content and deliver faster, more scalable pages.
Installation
Add the bundle to your composer.json:
composer require alengo/sulu-http-cache-bundle
Enable it in config/bundles.php:
return [
// ...
Alengo\SuluHttpCacheBundle\SuluHttpCacheBundle::class => ['all' => true],
];
Configuration Publish the default config (if needed):
php bin/console sulu:http-cache:install
Override defaults in config/packages/sulu_http_cache.yaml:
sulu_http_cache:
tracking_params: ['utm_source', 'utm_medium', 'utm_campaign'] # Customize as needed
cookie_prefix: 'cta_' # Prefix for marketing cookies
# 1.0.0: referer validation is on by default — add every host you
# legitimately receive attribution traffic from (see Gotchas).
trusted_referers:
- 'www.example.com'
- 'campaign.example.com'
excluded_paths:
- '^/api/'
- '^/_admin/'
Upgrading to 1.0.0 This is the first stable release; the public services and event classes are unchanged, but validation is stricter. Before deploying:
php bin/console cache:clear so compiled patterns are rebuilt.excluded_paths / tracking_params for unescaped regex characters (see Gotchas).Referer header — the hardened check depends on it.First Use Case Cache-Breaking Query Parameters Strip tracking params from cached responses:
use Alengo\SuluHttpCacheBundle\Cache\CacheAwareRequest;
$request = new CacheAwareRequest($originalRequest);
$cleanUrl = $request->getUri(); // Automatically strips tracking params
Marketing Cookie Handling Store attribution cookies at the reverse-proxy layer:
$this->get('sulu_http_cache.cookie_handler')->storeCookie(
'cta_campaign_id',
'summer_sale',
['lifetime' => 3600]
);
Workflow:
CacheAwareRequest to clean URLs before caching.RequestStack for global access:
$request = $this->get('request_stack')->getCurrentRequest();
$cleanRequest = new CacheAwareRequest($request);
Symfony Event Integration
Listen to kernel.request to auto-sanitize requests:
use Alengo\SuluHttpCacheBundle\EventListener\CacheAwareRequestListener;
services:
Alengo\SuluHttpCacheBundle\EventListener\CacheAwareRequestListener:
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
Referer-Aware Attribution (1.0.0)
The bundle now validates the Referer against the configured hosts before it will persist an attribution cookie. In multi-domain or CDN-fronted setups, make sure the origin host is present in trusted_referers:
sulu_http_cache:
trusted_referers:
- 'www.example.com'
- '*.example.com' # wildcards are supported, but compiled strictly
If you proxy through a CDN, the referer seen by PHP is whatever the edge forwards — do not strip it in your VCL/nginx config.
Reverse-Proxy Layer Handling
cta_campaign_id) in the SuluHttpCacheBundle config.CookieHandler service to manage cookies:
$this->get('sulu_http_cache.cookie_handler')->setCookie(
'cta_source',
'facebook',
['path' => '/', 'secure' => true]
);
Cookie Payload Validation (1.0.0) Cookie values are now validated against an expected payload shape before being written or read back. Malformed, oversized, or control-character-containing values are discarded instead of being stored. Validate up front when values are user-derived:
if (!$this->get('sulu_http_cache.cookie_handler')->isValidPayload($value)) {
// skip or normalise before storing
}
Keep payloads scalar and short (campaign ids, source names, timestamps). Do not stuff serialized objects or base64 blobs into attribution cookies — they will be rejected.
Dynamic Cookie Storage
CookieHandler to support custom storage backends (e.g., Redis):
sulu_http_cache:
cookie_storage: 'redis://localhost:6379/0'
Custom backends must round-trip the validated payload unchanged; do not mutate or re-encode values in the backend adapter.Custom Cache Keys Override the default cache key logic in a subscriber:
use Alengo\SuluHttpCacheBundle\Event\CacheKeyEvent;
public function onGenerateCacheKey(CacheKeyEvent $event) {
$event->setKey(md5($event->getRequest()->getPathInfo() . $event->getTrackingParams()));
}
Symfony Cache Integration
Use the bundle’s cache key with Symfony’s HttpCache:
use Alengo\SuluHttpCacheBundle\Cache\CacheKeyGenerator;
$generator = new CacheKeyGenerator($this->getParameter('sulu_http_cache.tracking_params'));
$cacheKey = $generator->generate($request);
Pattern Compilation (1.0.0)
tracking_params and excluded_paths are now compiled into escaped, anchored regular expressions rather than being used loosely. This means:
^/api/ is safe..+, .*, (, [) must be intentional and valid — invalid patterns now fail fast at container compile time instead of silently never matching.cache:clear; the compiled set is cached.Varnish/Nginx Configuration
Configure your reverse proxy to respect the X-Sulu-Cache-Key header:
location / {
set $cache_key $request_uri;
if ($http_x_sulu_cache_key) {
set $cache_key $http_x_sulu_cache_key;
}
proxy_cache_key "$cache_key";
}
Also ensure Referer is forwarded untouched:
proxy_set_header Referer $http_referer;
Header-Based Cache Control Add cache headers dynamically:
use Alengo\SuluHttpCacheBundle\Response\CacheResponse;
$response = new CacheResponse($content, 200, [
'Cache-Control' => 'public, max-age=3600',
]);
Tracking Param Whitelisting
sulu_http_cache.tracking_params can cause cache misses.*) cautiously—validate params server-side first.Cookie Scope Conflicts
cta_* vs. existing cookies) may cause conflicts.cookie_prefix and audit existing cookies.Reverse-Proxy Mismatch
X-Sulu-Cache-Key, cached responses will use raw URLs.curl -H "X-Sulu-Cache-Key: test" and verify headers.Dynamic Content Leaks
Vary: Cookie headers.Referer Rejections After Upgrading (1.0.0)
Referer host isn’t in trusted_referers, or if a CDN/proxy strips the header.trusted_referers, confirm proxy_set_header Referer $http_referer;, and test with curl -H "Referer: https://www.example.com/" .... Watch the log for rejected-referer entries.Cookie Values Now Rejected (1.0.0)
;/newlines) are now dropped by payload validation.storeCookie()/setCookie(). Add a test that asserts a round-trip of your real campaign values; failures are silent by design (to avoid poisoning responses).Compiled Pattern Regressions (1.0.0)
^ anchor, an unbalanced bracket, or an unescaped . can all change behaviour.excluded_paths and tracking_params as regexes and test them explicitly:
php bin/console cache:clear && php bin/console debug:config sulu_http_cache
Run your exclusion list against real paths in a unit test.Log Cache Keys Enable debug mode to log generated cache keys:
sulu_http_cache:
debug: true
Check logs for SULU_HTTP_CACHE_KEY entries.
Diagnose Dropped Cookies / Referers
With debug: true, the 1.0.0 validation paths log why a cookie or referer was rejected. If attribution data is missing but no exception was thrown, look here first — rejections are intentionally non-fatal.
Inspect Compiled Patterns
After cache:clear, dump the compiled rules from the container to confirm what actually got built:
php bin/console debug:container --parameter=sulu_http_cache.tracking_params
Validate Cookie Storage
Use bin/console debug:container sulu_http_cache.cookie_handler to inspect stored cookies.
Custom Cache Key Logic
Extend CacheKeyGenerator to support:
?locale=fr).Cookie Storage Backends
Implement Alengo\SuluHttpCacheBundle\Cookie\CookieStorageInterface for:
Event-Driven Extensions
Subscribe to sulu_http_cache.cache_key_generated to modify keys pre-caching:
use Alengo\SuluHttpCacheBundle\Event\CacheKeyEvent;
public function onCacheKeyGenerated(CacheKeyEvent $event) {
if ($event->getRequest()->getPathInfo() === '/promo') {
$event->setKey('promo_' . $event->getKey());
}
}
Custom Referer Rules If your trust model is more complex than host matching (e.g., signed campaign links), decorate the referer validator service and delegate to the built-in check for the default case rather than replacing it — the 1.0.0 hardening covers normalisation edge cases you would otherwise have to reimplement.
CookieHandler::flush() to clear stale cookies in bulk during migrations.X-Sulu-Cache-Key headers.sulu_http_cache:
excluded_paths:
- '^/api/'
- '^/_admin/'
tracking_params to what you actually report on.How can I help you explore Laravel packages today?