-3

I have the following at the beginning of my callable PHP scripts (Example: mytest.php)

#!/usr/bin/env php
<?php

This works exactly as hoped when called from the command line: the opening line is interpreted by the shell and PHP is called accordingly without any output to the terminal.

But if I do:

include('mytest.php') ;

in some other script, then that comment line gets output to the terminal (or, worse, to a web page). This looks like a bug to me since PHP should also interpret # as a comment, but in any case I would love to avoid the extra line of output. Looking for a way to make that comment line actually be ignored within include() ... or what suggestions to avoid the scenario?

> php --version 
PHP 7.4.3-4ubuntu2.17 (cli) (built: Jan 10 2023 15:37:44) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
    with Zend OPcache v7.4.3-4ubuntu2.17, Copyright (c), by Zend Technologies
    with Xdebug v3.0.4, Copyright (c) 2002-2021, by Derick Rethans
Dennis
  • 1,071
  • 2
  • 17
  • 38
  • normally you wouldn't include a php script that was also meant to be run from command line. You don't need the !# if you run it directly using `php myscript.php` – Garr Godfrey Jan 30 '23 at 20:31
  • 1
    Does this answer your question? [How to ignore first line with php include?](https://stackoverflow.com/questions/24571084/how-to-ignore-first-line-with-php-include) – Garr Godfrey Jan 30 '23 at 20:33
  • Thanks, @GarrGodfrey, I understand that a script should be specially written to serve as both a primary script and a subordinate. In this case, that work has been done, and while the files may be split in the future, this is what we have now. I'm currently looking into your other comment. – Dennis Jan 31 '23 at 02:40

2 Answers2

0

When you use include PHP is internally reading the file and including it where your include directive is. It's akin to copying and pasting the file contents into the location where the include directive is, but without being inside a PHP code block.

For example: file1.php

#!/usr/bin/env php
<?php
  //file 1 code
?>

file2.php

<?php
  // some code
  include 'file1.php';
  // some more code
?>

Results in the following:

<?php
  //some code
?>
#!/usr/bin/env php
<?php
  //file 1 code
?>
<?php
  // some more code
?>

Because the #! is outside of the PHP start/end tags (<?) it's treated as raw text to output and PHP is not looking to see if there are comments there. This is correct and expected behaviour.

As for the the shebang line itself (sorry if this seems condescending, it's just to be absolutely clear to other readers), is parsed and processed by the kernel when you execute a file, not PHP. When you attempt to execute a script, the kernel checks the first line of the script (the shebang line) to see if it starts with "#!". If it does, the kernel knows that the script requires an interpreter to execute it.

The kernel extracts the path specified in the shebang line, which points to the desired interpreter. In the example above, it would extract /usr/bin/env php.

The kernel then executes the specified interpreter and passes the path of the script as an argument to the interpreter. The interpreter (in this case, PHP) takes over and processes the script according to its syntax and semantics.

As the PHP cli executable knows and supports the shebang syntax, it skips this one line when processing this one file at startup, it will not look for this again. As such, your included file will output any content either from a PHP echo or content that is not contained with the PHP code block tags.

You can prove this to yourself by creating the following file and executing it

#!/usr/bin/env php
#This will output to STDOUT, it's not a comment because it's outside of the PHP code blocks
<?PHP
# This is a comment
?>

Which results in:

geoff@pc:~$ ./test.php 
#This will output to STDOUT, it's not a comment because it's outside of the PHP code blocks

The fact that you are having this issue isn't due to PHP but rather a design fault of your application, a script to execute on the command line should never be used as a file to include (as you have discovered). If you need two separate entry points for your code, you need to put your common code in a common file, for example:

common.php

function someFunction()
{
  //DoStuff
}

command.php

#!/usr/bin/env php
<?PHP
include 'common.php';
someFunction();
?>

index.php

<?PHP
include 'common.php';
someFunction();
?>
Geoffrey
  • 10,843
  • 3
  • 33
  • 46
-2
#!/usr/bin/env php

Is NOT a comment, it's a shebang telling the kernel how to interpret the contents of the file.

If you want to "catch" the output of a file you can use ob_start, ob_get_contents() and ob_end_clean like so:

<?php

ob_start(); // turn on output buffering

include "mytest.php";

$contents = ob_get_contents();

ob_end_clean(); // turn off output buffering

Then you can examine and filter the "comment" out of the output.

However, I'm not actually able to reproduce the issue on my computer (php v8), but that is how you can catch any output generated by the included PHP file.

Marco
  • 7,007
  • 2
  • 19
  • 49
  • It IS a comment, when it's not at the beginning of the code. It just happens to "look like" a shebang in that scenario. Anyway, the same question applies without the bang. And ob_start won't work here given that, when the file is the main script, I do need the shebang. – Dennis Jan 31 '23 at 02:38
  • Time limit ran out after I realized what you were saying with ob_start. I will look into it. – Dennis Jan 31 '23 at 02:45
  • @Dennis What you're saying doesn't make much sense `It IS a comment, when it's not at the beginning of the code.` in your code IT IS at the beginning of the code, so IT IS a shebang. – Marco Jan 31 '23 at 15:36
  • @Dennis I suggest you take a step back and re-phrase what you're really wanting to achieve here. I've never encountered the problem you describe. – Marco Jan 31 '23 at 15:38
  • it is not at the beginning of the code when it's included. That's what I'm saying, and where your "it's a shebang" becomes wrong. At any rate, _definition_ of a comment includes "unix-style comments," and in turn unix-style comments (for example bash) definition says about hashsign: 'a word beginning with ‘#’ causes that word and all remaining characters on that line to be ignored.' There is no distinction for the presence or absence of the bang (!) – Dennis Jan 31 '23 at 20:03
  • @Dennis That is not how `include`s in PHP work and it actually doesn't matter. If the first line of a file starts with `#!` then it's a shebang. – Marco Jan 31 '23 at 21:44
  • My final attempt to help you undestand: Shebang is used only by the kernel, to determine what process (usually a shell) should be called to process this particular file. (https://linuxhandbook.com/shebang/). The kernel _never_sees_this_line - it's fed into PHP by PHP. Again, while it looks like a shebang, it happens to be a comment. I've wasted enough time on this, which, by the way is completetly off topic from the question, and is instead a deterrent to finding an answer to the stated question. – Dennis Feb 02 '23 at 21:03
  • @Dennis `The kernel _never_sees_this_line - it's fed into PHP by PHP` no - the kernel sees everything but that isn't relevant here. What's also irrelevant is the fact that you don't consider this a shebang. `#` is the start marker of a comment _in PHP_, **not** _regular_ text files. When you include a file via _PHP_ and said file doesn't start with `` (or ` – Marco Feb 02 '23 at 22:45
  • You're doing something _very_ weird and that's your problem. I don't need you to make me understand something **you** _clearly_ don't understand. – Marco Feb 02 '23 at 22:47
  • Thank you for the answer. I'll give it all the further attention it deserves. – Dennis Feb 04 '23 at 11:35