I decided to combine (and minify) some CSS files for our backend administration site, so I wrote the code to load, minify, and output the final stylesheet. I was very careful to write to a temporary file, check even the fclose()
return code, rename it into place, and so on. I even renamed the original to a backup so that I could attempt to rename it back if the first rename succeeded, but the second failed.
For style points, I updated it to set the last-modified time of the generated file to the timestamp of the latest input, so that If-Modified-Since headers will work correctly.
I tested it, multiple times, with various states of having the main and backup filenames. It looked great. I pushed it out to production… and that wasn’t so great.
We just had no styles at all. Yikes! I had some logic in there for “if production and minified CSS exists, use it; else, fall back to the source stylesheets.” I hastily changed that to if (false)
and pushed another deployment, so I could figure out what happened.
It didn’t take long. The web server log helpfully noted that the site.min.css
file wasn’t accessible to the OS user.
I had used tempnam()
, which created an output file with mode 600, rw- --- ---. Per long-standing philosophy, the deployment runs as a separate user from the web server, so a file that’s only readable to the deployer can’t be served by the web server. Oops.
I had considered the direct failure modes of all of the filesystem calls I was making, but I hadn’t considered the indirect consequences of the actions being performed. I added a chmod(0o644)
call and its error check, and deployed again. After that, the site worked.
No comments:
Post a Comment