$foo =~ s/baz/bum/;
A couple days ago a website stopped working, refusing to show anything below its top menu bar. I knew it was written in PHP, but I hadn't realized it used Smarty, a template engine. I didn't realize it before the outage, but one of Smarty's features is that it "compiles" (generates, really) template files into PHP code on the fly as they're accessed and/or updated. The idea is that if you need to change the template files, you just upload them; the next time that page is accessed, Smarty notices that it needs to recompile the PHP file, does so, and writes out the new file to a directory called "template_c".
This means that it needs to write to that directory (which Smarty docs recommend stay out of the DocumentRoot). But I hadn't turned that on, and in general this sort of thing makes me nervous. (Though I do allow it for other websites, so I'm not being very consistent here.)
The development machine has the files rooted at ~user/public_html; to deploy, we rsync to the server's /var/www/$PROJECT directory. The template_c files have already been compiled in the process of testing, and those compiled files include() other Smarty libraries -- and it specifies the full path to those libraries. Can you see where this is going?
As far as I can tell, what happened was:
The PHP was tested on the dev server; Smarty compiled the templates, and added include() directives or the library files using the full path to the user's home directory.
The PHP was copied into place on the web server and tested.
Smarty looked at the templates, found the compiled versions, and ran them. In the process, it tried to load other Smarty libraries.
It worked, because autofs mounted this user's home directory when requested.
Time passed.
On Wednesday, someone tried using the site. Autofs, for some reason, couldn't mount the developer's home directory, so Smarty couldn't include those files, and we saw nothing after the page's menu bar.
I got around this by using sed on the compiled template files to set the correct path to the library files, which at least got the site up again.
I'm still not sure what the hell went wrong with autofs. On this particular server I used to have a static map for home directories, and it doesn't work with the developer's home. I thought I had replaced that with an LDAP-based map a long time ago...but there it was, and I can't find anything in the Cfengine git repo that shows a change, or that I'd deployed the LDAP map in the first place. I pushed that out, and now this all works the way it should...
...except that it shouldn't work like this. I'm reluctant to let PHP write to the filesystem, but that's what Smarty expects. I think it supports relative paths -- gotta dig up my notes -- which'd be fine. (I saw one suggestion on the Smarty support forums to include "." in your PHP_INCLUDE path using .htaccess, which made me run around the room hollering and cursing) As a workaround, I'm going to move the development files to /var/www/$PROJECT on the dev server, which will match production; I'm unhappy with this because it breaks the real advantages Smarty brings, and makes the deployment process a bit harder...but I'm still a nervous nelly.
https://it.slashdot.org/comments.pl?sid=292329&cid=20539853 (NSFW, probably)
This is how I imagine Samuel L. Jackson leading off a conversation with the writers of the PHP language (edited to be less obscene and offensive).
In the name of all that is holy and right, please explain to me why
the fuck PHP's preg_replace()
takes delimiters for the first
argument, but not the second. IOW, Perl's
$foo =~ s/baz/bum/;
becomes
preg_replace('/baz/', 'bum', $foo);
Yes, I should've just RTFM. You're completely right. But this just bit me in the ass, after spending 10 minutes wondering WTF was going wrong, and a little fucking consistency goes a long fucking way.