make a PHP script executable from CLI and include-able? - php

Consider this:
#!/usr/bin/php
<?php
class Foo {
static function bar () {
echo "Foo->bar\n";
}
}
if (PHP_SAPI === 'cli') {
Foo::bar();
}
?>
I can execute this from CLI, but when I include it in, say, a CGI-run PHP script, the shebang ends up in the output.
I like simple scripts compact: I guess I could put the class part in a separate "lib"-file and have a simple wrapper for CLI use. BUT I'd like to keep it all in one place without having to worry about include paths etc.
Is this possible without ob_*-wrapping the include to capture the shebang (if this is even possible), or is it dumb to cram all of this into one file anyway? Alternatives/Thoughts/Best Practices welcome!
Edit: I'd like to put the script in my PATH, so calling I'd rather not call it by php file.php. See my comment to #misplacedme's answer

It's actually easy.
Remove the shebang and when you run the script, run it as
php scriptname.php OR /path/to/php scriptname.php
instead of
./scriptname.php
Running php script.php will look in only the current directory, or any directory within PATH. If you absolutely have to run it that way, add it. export PATH=$PATH:/path/to/php/script/folder(in bash)
That will mess up includes unless you're using full paths within the script.
No matter what you do, you'll have to use full paths somewhere.

I'm rather late to this one, but if anyone still cares, you can solve this on Linux by registering a binfmt handler.
As a one-off (resets after reboot):
echo ":PHP:M::<?php::/usr/bin/php:" > /proc/sys/fs/binfmt_misc/register
With this in place, any file that starts with the "magic" string "<?php" will be executed by running it with /usr/bin/php.
You can make this registration permanent by saving the line a file in /etc/binfmt.d
You can remove the registration with:
echo -1 > /proc/sys/fs/binfmt_misc/PHP

Related

Running script and executing PHP for output

I'm looking to run a program, and for every output line it generates, execute a PHP script and pass the line content to it.
I know, pretty hard to understand. Here's an example:
Execute script -> script outputs 'Initializing script on 127.0.0.1'. Now it needs to execute a command like php5 input.php 'Initializing script on 127.0.0.1'.
Is this doable? If so, how would I go about doing this?
Edit: to clarify; I basically want command > log.txt but in stead of writing the output to that file, writing it to a PHP script as an argument
PHP is an interpreter much like Bash, Python, etc, so you can do "normal" scripting with it. For example:
#!/usr/bin/php5
<?php
echo "Hello, world!\n";
while($line = fgets(STDIN)) {
echo "> " . $line;
}
?>
Mark the file as executable, then run:
$ /program/that/generates/lines | /path/to/your/php/script
However, contrary to your original question, it sounds to me like you actually want to use JavaScript and possibly AJAX for web purposes. Sane web applications will have the said script run in the background and safely write the results to a file or stream, using AJAX to read it and update the information on the current page.

PHP exec() re-executing same script again and again

Here I am writing about my flow in detail.
I am doing an Ajax request on same host.
AJAX call to saveUser.php
in saveUser.php, I have included Common.php.
Common.php have createFile1() and createFile2() function.
createFile1() function just creating a sample1.php for another purpose.
in createFile2(), I am creating a file sample2.php and executing a exec('php /home/public/sample2.php > /dev/null &'); command to execute that file.
I am calling this createFile1() and createFile2() function respectively from saveUser.php which is being called by an AJAX request.
As I have set the exec command to run in background by '&' at end of command, it is returning without waiting for the response and all goes smoothly in front.
But when I am checking on my server, these files sample1.php and sample2.php are getting created again and again. It seems all this saveUser.php action are getting executed again and again until I stops the sample2.php process from SSH.
I checked the processes list, each time 'php /home/public/sample2.php' is having new process_id, so it confirms that it is getting executed again and again. If I remove the exec() code and execute this sample2.php from SSH, it works as expected, there is not such problem.
Please suggest me whats going on wrong? Is there any problem with server configuration, I am using hostgator shared account.
Also I am including same Common.php file in sample2.php also, informing in case it can help it.
Thanks for your help in advance.
saveUser.php code
include_once dirname(__FILE__).'/Common.php';
createFile1();
createFile2();
echo 'saved successfully!';
Common.php code
function createFile1()
{
$template = file_get_contents('sendDmTemplate.php');
$serviceFp = fopen('sendDmFiles/sample1.php',"w");
fwrite($serviceFp , $fileContent);
fclose($serviceFp);
}
function createFile2()
{
$fileContent = file_get_contents(dirname(__FILE__).'/sampleFileTemplate.php');
$serviceFp = fopen('sample2.php',"w");
fwrite($serviceFp , $fileContent);
fclose($serviceFp);
exec('php '.dirname(__FILE__).'/sample2.php > /dev/null &');
}
sample2.php code
include_once dirname(__FILE__).'/Common.php';
echo 'hi';
This exact same thing happened to me. I was trying to have one php script call exec() on another php script but for some strange reason it would just exec() itself again creating an infinite loop. The currently accepted answer didn't get me anywhere, but I was able to get it to work by specifying an absolute path to php.
So, instead of
exec('php /home/public/sample2.php > /dev/null &');
it would be
exec('/usr/local/bin/php /home/public/sample2.php > /dev/null &');
Check the following:
1) Are you sure you are NOT calling your script saveUser.php multiple times? Mayby a codingerror somewhere in the javascript XHR? Check this by looking in the (apache?) log.
2) Are you sure your php executes alright without the -q? I use php -q pathtoscript.php
3) If not 1 or 2: Post the code in here (or somewhere) of saveUser.php
EDIT: I see your problem. The file you create includes common.php again, and executes that again. Etc. <-- wrong Oops. I wrote that too early. Looking into it again now.
4) Is it possible you use some errorhandling that redirects to your saveUser.php?
Edit:
5) There might arise a problem from the fact that you are including the file that is executing the command itself in combination with include_once, but I am not sure. You could simply test this by changing your content of sample2.php content by adjusting sampleFileTemplate.php. Create a common2.php (with identical content as common.php), and use that one. COuld you testdrive that setup and report back?

Passing Params from PHP to Powershell exec

I am attempting to write a PHP script that will allow for me to select a few files to download from a predetermined location. I'd like my script to pass an array to a Powershell script that id written earlier and have my Powershell script handle the downloading (basically the php file just needs to tell the powershell file what needs to be downloaded).
I've looked at a few options, and it seems that exec is the command I should use for this (as I do not care about command line output I shouldnt need shell_exec).
So far I've turned OFF safe mode to allow me to use this command. I should also note that the php file will be run from a server, however the powershell files are located on a local machine.
A snippet of the code so far to handle the param passing looks like this:
if(isset($_POST['formSubmit']))
{
$choosePlugin = $_POST['wpPlugin'];
$chooseTheme = $_POST['wpTheme'];
if(isset($_POST['wpTheme']))
{
echo("<p>You selected: $chooseTheme</p>\n");
exec('powershell.exe C:\Wordpress Setup\setupThemes.ps1 $chooseTheme');
}
else
{
echo("<p>You did not select a theme</p>\n");
}
I am a bit confused as to what I should put inside the exec. When I run the above code there are no errors however nothing happens. I am a bit new to this so I apologize if more information is required. Any help is appreciated thank you.
Try to do:
echo exec('powershell.exe C:\\Wordpress Setup\\setupThemes.ps1 $chooseTheme');
to see the results of powershell.exe (remember the double \), also make sure to put the absolute path to the exe file:
echo exec('c:\\PATH_TO_POWERSHELL.EXE\\powershell.exe C:\\Wordpress Setup\\setupThemes.ps1 $chooseTheme');
If you want to pass the contents of the variable you should use double quotes to actually expand it, I guess. Furthermore you should quote the script name because the path contains spaces:
exec("powershell.exe \"C:\Wordpress Setup\setupThemes.ps1\" $chooseTheme");

Running web-intended PHP code from command line

I have PHP code that requires other php files by address $_SERVER['DOCUMENT_ROOT'].'/subdir/file.php';
First of all -- is this the best proper way to include things? Obviously I don't want to use path like '../../subdir/file.php'; because moving the file would break it.
But another interesting issue is that if I run this file through command line then $_SERVER is not created. I can fake it via $_SERVER['DOCUMENT_ROOT'] = '.'; but I'm curious to if this is the best practice. Seems like not.
Edit: Obviously there are many ways to skin this cat, although I think the best practice is to define a variable (or a constant) responsible for the include directory. Such as:
define('INC_DIR', $_SERVER['DOCUMENT_ROOT'].'/../includes');
or
if (PHP_SAPI == 'cli') {
$_includes = '../includes';
} else {
$_includes = $_SERVER['DOCUMENT_ROOT'].'/../includes/');
}
And use the aforementioned variable or constant throughout the code.
I prefer to use a folder definition system in my architectures. Something like this:
define( 'DIR_ROOT',dirname(__FILE__) );
That works both in command line and web mode. Use that in your application entry point (index.php in most cases) and then load the rest of your framework from that file outward. All inbound calls to your application should be routed via .htaccess or other method so that they call index.php?foo=bar etc.
I also hate typing DIRECTORY_SEPARATOR all the time so I usually make the first definition:
define( 'DS' , DIRECTORY_SEPARATOR );
This enables you later to do something like this:
require_once( DIR_ROOT.DS.'myfolder'.DS.'myfile.class.php' );
Alternatively if you don't want or need to modify your php files and you just need a page to be executed normally you could use curl. Most Linux and Unix systems have it installed.
$ curl http://www.example.com/myscript.php &> /dev/null
The &> /dev/null part sends the output into a black hole in the system so you don't have to see the HTML which was returned by the request.
if(PHP_SAPI == 'cli')
{
$_SERVER['DOCUMENT_ROOT'] = '/path/to/webroot';
}

Calling php from php through exec() gives no result

I have a PHP script that creates other PHP files based on user input. Basically, there are files containing language specific constants (define) that can be translated by the user. In order to avoid runtime errors, I want to test newly written files for parse errors (due to "unusual" character sequences). I have read several posts here on SO (like PHP include files with parse errors) and tried a function that uses
$output = exec("php -l $filename");
to determine whether a file parses correctly. This works perfectly on my local machine, but at on the provider's machine, the output of calls to exec("php ...") seems to be always empty. I tried a call to ls and it gives me output, leading me to the assumption that PHP is somehow configured to not react to command line invocations or so. Does anyone know a way around this?
EDIT: I forgot to mention, I had already tried shell_exec and it gives no result, either. In response to sganesh's answer: I had tried that too, sorry I forgot to mention. However, the output (second argument) will always be an empty array, and the return value will always be 127, no matter if the PHP file to test has syntax errors or not.
I had the same problem. The solution that worked for me was found in running-at-from-php-gives-no-output. I needed to add output redirection.
$output = exec("php -l $filename 2>&1");
You can try with exec second and third arguments.
second argument will have the output of the command.
third argument will have the return value.
And exec will return only last line of the command.
$filename = "a.php";
$output = exec("php -l $filename",$op,$ret_val);
print $output."\n";
print $ret_val."\n";
var_dump($op);
By executing shell_exec(), you can see the output as if you executed that file via command line. You can just see if there is an error right here.
<?php
if (strpos(shell_exec('php -l file.php'), 'Syntax Error')) {
die('An error!');
}
There may also be a possibility that shell_exec() or exec() may be disable by your host.
Nice idea to check the file validity :-)!
Now, from the PHP manual for exec():
Note: When safe mode is enabled, you can only execute files within the safe_mode_exec_dir. For practical reasons, it is currently not allowed to have components in the path to the executable.
Can you check if this is not the case for you?
Also, can you check by providing the full path of the PHP interpreter in the exec() instead of only php. Let me know how you fare.
Pinaki
the correct way is to add >2&1 as tested on a windows system using imagemagick!
I worked around my original problem by using a different method. Here is what I do now:
Write a temporary file with contents <?php include "< File to test >"; echo "OK"; ?>
Generate the correct URL for the temporary file
Perform HTTP request with this URL
Check if result equals "OK". If yes, the file to test parses without errors.
Delete temporary file
Maybe this could be done without the temporary file by issuing an HTTP request to the file to test directly. However, if there is a parse error and errors are suppressed, the output will be empty and not discernible from the output in the case of a file that gives no parse errors. This method is risky because the file is actually executed instead of just checked. In my case, there is only a limited number of users who have access to this functionality in the first place. Still, I'm naturally not entirely happy with it.
Why the exec() approach did not work, I still do not know exactly. pinaki might be right by suggesting to provide the full path to the PHP executable, but I cannot find out the full path.
Thank you everyone for answering, I upvoted you all. However, I cannot accept any of your answers as none of your suggestions really solved my problem.

Categories