I probably should have seen this coming, but when introducing Twig to a non-Symfony project, it hadn’t occurred to me to expect the same permissions dance that Symfony cover helpfully in their setup guide.
Having built a shiny new system that uses the same template cache for web requests (handled by the Apache user) and emailed reports (handled by another user via cron / command-line invocation), of course I hit exactly the same problem that those steps avoid. If you share any templates across the two users’ remits, eventually one will want to write to an existing cache file generated by the other user. It won’t have write permission, and Twig will freak out:
Uncaught exception ‘RuntimeException’ with message ‘Unable to write in the cache directory (…/cache/twig/…).’ in …/vendor/twig/twig/lib/Twig/Environment.php:1239
One approach to get around this is to change Twig’s behaviour in handling the files. I found a nice post here describing a process which I expect would also have worked, which involves extending
Twig_Environment. However as this is an issue specific to where I’m deploying, I was hoping for a filesystem-level fix – preferably not something which required overriding Twig’s behaviour or creating a separate cache for each user.
Maybe this should be common sense but it took me a few minutes to work out. I had a system running CentOS, configured via cPanel in the days before I was slightly braver with sysadmin Linux-y things. For some reason the standard config comes with root SSH access and no sudo. And the OS had no
chmod +a support or ACLs enabled.
So my complete steps to get this working – where
MYUSER is my CLI task invoking user – were:
- SSH in as
root– or (preferably) don’t and use sudo for all the below
yum install acl– if you’re on a Redhat-based Linux flavour like CentOS
cp /etc/fstab /etc/fstab.bak
,aclto the options for the main partition (e.g.
/) and save (Ctrl + O, [return], Ctrl + X)
mount -o remount /(assuming the partition is at
/) to make ACL support kick in
cdto just above your cache directory – let’s assume it’s called
- Then we can just borrow all the clever bits from Symfony’s guide:
rm -rf cache
HTTPDUSER=`ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\ -f1`
setfacl -R -m u:"$HTTPDUSER":rwX -m u:MYUSER:rwX cache
setfacl -dR -m u:"$HTTPDUSER":rwX -m u:MYUSER:rwX cache
Done! The server now speaks ACL, and Twig should play happily with both PHP users.