When do file extensions override shebang lines on Linux?
Some PHP cron jobs started failing on a shared server recently. They had been working without error and no updates for nearly a year, but now would no longer run due to syntax errors. What was going on?
It turns out these scripts were suddenly now running under PHP 4, not PHP 5. There is a version of PHP 4 installed at /usr/local/bin/php, but this was the "shebang" line on these scripts:
#!/usr/local/php5/bin/php
I did some experiments:
% /usr/local/php5/bin/php --version
PHP 5.2.6 (cli) (built: May 11 2008 13:09:39)
Copyright (c) 1997-2008 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2008 Zend Technologies
with Zend Extension Manager v1.2.2, Copyright (c) 2003-2007, by Zend Technologies
with Zend Optimizer v3.3.3, Copyright (c) 1998-2007, by Zend Technologies
% echo '<?= phpversion() ?>' | /usr/local/php5/bin/php
5.2.6
% printf '#!/usr/local/php5/bin/php\n<?= phpversion() ?>' > version
% chmod +x version
% ./version
5.2.6
% mv version x.php
% ./x.php
4.4.9
I didn't know Linux would let file extensions override shebang lines, but that's what I'm seeing. Support at the hosting company had no idea why this was happening (or what had changed recently to make it happen), so I went with a workaround: rename the scripts so they no longer end in ".php".
The cron jobs are running again, but I hate a "just don't do that" answer. I'm really curious to know where this behavior is coming from, because I've never seen anything like this from *nix at the shell level. I tested under both zsh and bash, so I don't think I can blame a shell configuration. I grepped for 'php' under /etc to see if that would give me any clues, but no. Any ideas?
Sounds like you have php registered with binfmt_misc.
Check out the man page on the subject: binfmt_misc.txt
You'll want to unregister the php binfmt_misc handler by echoing -1 to it (must be root). It will be listed in /proc/sys/fs/binfmt_misc/ if this is your issue.
As a warning, this could break other stuff on the system. For instance, if another PHP script is being executed but doesn't have a valid shebang. CGI or suExec could be issues depending on their configuration. In short, be sure to test everything.
It does look like binfmt_misc, and your hosting company does seem to be a bit crazy :) But I suspect they've probably done this for compatibility, making .php files use php4, and php5 files use php5. Try a php5 extension. It shouldn't be necessary to do this for all the files on a site (just cronjobs and other things run as server jobs/scripts) because your webserver will have its own execution logic/handlers.