How can I avoid showing "#!/usr/bin/php" on PHP? How can I avoid showing "#!/usr/bin/php" on PHP? shell shell

How can I avoid showing "#!/usr/bin/php" on PHP?


I solved the problem using output buffering.My script now looks like this:

#!/usr/bin/php<?php@ob_end_clean();...

Note: There is no ?> at the end of the file. This is actually a good practice when writing PHP scripts. This prevents any garbage text to be accidentally printed.

Note: The PHP documentation for ob_end_clean() says that:

The output buffer must be started by ob_start() with PHP_OUTPUT_HANDLER_CLEANABLE and PHP_OUTPUT_HANDLER_REMOVABLE flags. Otherwise ob_end_clean() will not work.

It seems that this is done automatically when PHP runs from command line.


There is no need to have #!/usr/bin/php in your code, just run CLI script using php, for example php /path/to/file.php or /usr/bin/php /path/to/file.php.


@ViliamSimko's wicked trick is almost there, but, unfortunately, flawed. (It did actually break my header-sending sequence, for instance, despite not polluting the output with the shebang.)

TL;DR, here's the fix*:

#!/usr/bin/php<?php @ob_end_clean(); if(ini_get('output_buffering')) ob_start();...

or, less obscene-looking, but still just an euphemism for the same offense ;) :

#!/usr/bin/php<?php if (ob_get_level()) { ob_end_clean(); ob_start(); }...

(And see also the "UPDATE" part below for perhaps the maximum we can do about this...)

Explanation:

@Floris had a very good point in the comments there:

Do you need an ob_start(); as well? Probably worth mentioning.

You sure do. But where? And when?

Cases to consider:

  1. As Viliam said (and just confirmed it with PHP 7.2), the shebang is fortunately eaten by the php command itself, when you run your script with php yourscript.php, so the entire trick is redundant.

  2. In web mode, it's actually config-dependent: if output_buffering is on in the config (and sure enough, it's usually on, but it's not even the default), an ob_start has already been done implicitly at the start of the script (you can check it with ob_get_level()). So, we can't just abruptly cancel it with an ob_end_clean and call it a day: we need to start another one, to keep the levels balanced!

  3. If output_buffering is off in the config, then, sad face, we are out of luck: ob_get_clean() does nothing, and the shebang will end up in the top of the page.

    Note: there is no fix for this one, other than turning it on.

  4. In command-line mode, the manual says about output_buffering:

    This directive is always Off in PHP-CLI.

    But, instead of failing the same hopeless way as in 3., the implicit shebang cleanup (see 1.) saves the day.


* "Fix" in the sense that this audacious hack will work in a lot more cases. If you are in full control of your PHP env., it can be just fine (as is in my case). Otherwise, it can still break in lots of subtle ways unexpectedly (consider auto-prepended code, custom extensions, or other possible ways to control output buffering etc.). Also, for example, when included from other scripts in CLI mode (where there's no buffering), you are still out of luck: the shebang will show up in the output, no matter what (unless, of course, filtered out manually by the caller). Not only that, but it would also break up your own buffering, if you happened to have any, while including such a naughtified script.


UPDATE: Just for the fun of it, here's an "almost correct" version, which plays along nicely with an ongoing buffering, be it implicit or user-level:

#!/usr/bin/php<?phpif (ob_get_level()) {    $buf = ob_get_clean();    ob_start();    // Refill the buffer, but without the shebang line:    echo substr($buf, 0, strpos($buf, file(__FILE__)[0]));} // else { out of luck... }

Still only "almost" correct, as nothing can fix output_buffering = 0 in web mode, and the "being included with no buffering" case can only be solved if the calling script adds an explicit ob_start - ob_end_... wrapping. Also, most of the caveats above still apply: various subtleties can still break it (e.g. the current output buffer must have the (fortunately default) PHP_OUTPUT_HANDLER_CLEANABLE flag etc.).)