I have a problem in using system(), passthru() and exec(), the example below will describe it better, I have a string x that I will use it as argument for system():
$x = ' second_string' .$array[$i];
system("cat $x "); // not working
system("cat ".$x); // not working
system("cat { $x }"); // not working
system('cat "' . $x . '" '); // not working
system("cat second_string_xx.txt" ); //working !!
Your question couldn't be more vague but one of your comments suggest that you expect an error message when you feed cat with an invalid file. Well, that's not how cat actually works. As most classic Unix commands, it writes error messages into standard error (stderr) rather than standard output (stdout). You either need to use a PHP function that allows to capture stderr (such as proc_open) or redirect stderr to somewhere else (such as stdout or a file).
Apart from that, PHP program execution functions have many optional parameters and return values and you are ignoring them all. For instance, system() returns the last line of the command output on success (and FALSE on failure) and allows to capture the return value (which will be non-zero in case of error and is the standard mechanism to detect errors).
Related
This is my code for executing a command from PHP:
$execQuery = sprintf("/usr/local/bin/binary -mode M \"%s\" %u %s -pathJson \"/home/ec2/fashion/jsonS/\" -pathJson2 \"/home/ec2/fashion/jsonS2/\"", $path, $pieces, $type);
exec($execQuery, $output, $return);
the $return value is always 0 but $output is empty. The $output should be a JSON.
If I execute the same but removing one letter to binary (for example /usr/local/bin/binar ) I get (correctly) a $return = 127.
If I write other parameters (like -mode R which doesn't exit) I got errors from the console (which are correct as well).
If I run the exact $execQuery (which I printf before to be sure about quotation marks) on the console, it executes correctly. It's only the PHP side where I've got the error.
What can be wrong?
Thank you in advance.
Well, a couple of things might be happening...
This binary you're running write to something else that STDOUT (for instance, STDERR)
The env vars available to the PHP user differ from the env vars available to the user running console (and those vars are required)
PHP User does not have permission to access some files involved.
In order to debug, it might be better to use proc_open instead of exec, and check the STDOUT and STDERR. This might give you additional information regarding what's happening.
Suggestion (and shameless advertising)
I wrote a small utility library for PHP that executes external programs in a safer way and provides aditional debug information. It might help you to, at least pinpoint the issue.
I'm trying to read python output from a php webapp.
I'm using $out = shell_exec("./mytest") in the php code to launch the application, and sys.exit("returnvalue") in the python application to return the value.
The problem is that $out doesn't contain my return value.
Instead if I try with $out = shell_exec("ls"), $out variable contain the output of ls command.
If I run ./mytest from terminal it works and I can see the output on my terminal.
sys.exit("returnvalue")
Using a string with sys.exit is used to indicate an error value. So this will show returnvalue in stderr, not stdout. shell_exec() only captures stdout by default.
You probably want to use this in your Python code:
print("returnvalue")
sys.exit(0)
Alternatively, you could also use this in your PHP code to redirect stderr to stdout.
$out = shell_exec("./mytest 2>&1");
(In fact, doing both is probably best, since having stderr disappear can be quite confusing if something unexpected happens).
i've got this snazzy python code:
import subprocess
value = subprocess.Popen(["php","./php/php_runner.php"],stdout=subprocess.PIPE);
the problem is, i have no idea how to check if the php_runner, well, ran. Currently, it has the following salient sections:
if (count($argv) != 4){
die("four arguments are needed\n");
}
and
$returnValue = call_to_another_php_class();
return $returnValue;
So what i want is this:
How do i get the return value, whatever it may be, using python?
You probably are going to tell me to use "PIPE" in the answer, but the (to me, incomprehensible) python docs (http://docs.python.org/library/subprocess.html) state:
Do not use stdout=PIPE or stderr=PIPE with this function. As the pipes are not being read in >the current process, the child process may block if it generates enough output to a pipe to fill up >the OS pipe buffer.
So what do i use then, because while I don't really know what they're barking on about, i sit up and take note about notes in grey boxes. Pity they didn't spell out what i'm meant to do - but, well, what am i meant to do?
the "returnValue" that my php code returns, is that what python is going to pickup as the return value from the function? If not, how do i return that value?
cheers!
UPDATE
Thanks to the given answer, here's the changes i made:
edited /etc/php5/cli/conf.d/mcrypt.ini (actually, this is just a change for ubuntu 10.04, and I changed the first line to begin with a ; instead of a #. That stopped an annoying "we don't like #" error that kept popping up)
in my php, I changed the code to read:
if (count($argv) != 4){
fwrite(STDERR, "four arguments are needed\n");
exit(1); // A response code other than 0 is a failure
}
this puts my error value as an error. the die() command wasn't doing that for me.
changed the python to read:
value = subprocess.Popen(["php","./php/php_runner.php"],stdout=subprocess.PIPE,
stderr=subprocess.PIPE);
print value.communicate();
Yeah, realistically, i'd do an if on value.communicate()[1], becase that is where the errors are.
$returnValue = call_to_another_php_class();
if ($returnValue == 1){ //hah, php has a good return value as 1.
//no problem
} else {
fwrite(STDERR,get_error_from_php_class());
exit(1);
}
booyah!
Since you're using the Popen constructor rather than the call functions, those notes about PIPE don't apply to you.
Use .communicate() as documented to wait for the program to finish and get the output.
Is it possible to create an interactive shell, using PHP alone?
I mean something like you have with databases, Python, etc. If it is, how?
Yes, it's possible. In order to be interactive, the program must be able to wait for and read in user input from stdin. In PHP, you can read from stdin by opening a file descriptor to 'php://stdin'. Taken from an answer to different question, here's an example of an interactive user prompt in PHP (when run from the command line, of course):
echo "Continue? (Y/N) - ";
$stdin = fopen('php://stdin', 'r');
$response = fgetc($stdin);
if ($response != 'Y') {
echo "Aborted.\n";
exit;
}
Of course, to get a full line of input rather than a single character, you'd need fgets() instead of fgetc(). Depending what your program/shell will do, the whole program might be structured as one big continuous loop. Hopefully that gives you an idea how to get started. If you wanted to get really fancy (CLI pseudo-GUI), you could use ncurses.
Since this question has been asked and answered, a better solution has been added to PHP. In all recent PHP versions, at least PHP 5.4, you can easily get user input as so:
$input = fgets(STDIN);
The way I understand your question you just want the PHP interpreter to run on the command line so you that it will evaluate any PHP code that you type. I use that feature of Python all the time to test code snippets. In which case I believe the answer you are looking for is to execute (from the command line):
php -a
Assuming PHP is in your path this will drop you in to the PHP interpreter, like it does on mine:
php -a
Interactive shell
php >
From there you can start to evaluate arbitrary PHP expressions and see the results:
php > $a = 'abcdef';
php > echo strlen($a);
6
Here's an expanded take on this. I've added an isCLI() check in case you're run your script both in CLI and on a web server. Otherwise the server could loop using my function. This solution will prompt the user, check the input, and re-prompt the user for fixed input if necessary.
I rtrim() the input, because if the user uses return to submit their entry, that may be appended to the entry. Validation is not necessary; just don't pass a function in that case.
function isCLI() {
return (php_sapi_name() === 'cli' OR defined('STDIN'));
}
function userPrompt($message, $validator=null) {
if (!isCLI())
return null;
print($message);
$handle = fopen ('php://stdin','r');
$line = rtrim(fgets($handle), "\r\n");
if (is_callable($validator) && !call_user_func($validator, $line)) {
print("Invalid Entry.\r\n");
return userPrompt($message, $validator);
} else {
print("Continuing...\r\n");
return $line;
}
}
// Example =====================
function validateSetLangCode($str) {
return preg_match("/^[A-Z0-9]{3}-[A-Z]{2}$/", $str);
}
$code = userPrompt("Please enter the set / language codes. Use the format 'SET-EN', where SET is the three-letter set code and EN is the two-letter lang code. \r\n", 'validateSetLangCode') ?: 'SET-EN';
var_dump($code);
Since PHP has a built-in Unix-only function readline() to do exactly that, note:
We can use and hold the result of readline in a variable.
#!/usr/bin/php
<?php
$user = readline("List dir [l] | Say hello [h] | exit [q]: ");
if ($user === "l"){ system("ls"); }
if ($user === "h"){ echo "Hello!"; }
if ($user === "q"){ exit; }
echo "\nThanks!";
Example output:
l ls result
h «hello»
q exit
Ctrl + C exit.
Ctrl + D with empty input, continue to the next sequence. «Thanks». $user is defined and empty, no error.
Ctrl + D with some input: No action. Still waiting for input.
Ctrl + M Continue and take the current input in $user.
Ctrl + J Continue and take the current input in $user, same behavior as Ctrl + M.
Return continue to the next sequence «Thanks». $user can stay empty, no error.
Ctrl + Z may be used to cancel a loop and move to the top one. $user will be unset if the var is not defined in this scope.
Depending input, we can define empty values using!empty or do more surgical testings (the readline response can be many chars).
$user can be tested with !isset if not yet asked.
There is also the built-in readline_add_history() to store the user input into an object, where values can be retrieved directly by their name (nice for code clarity):
readline_add_history($user);
print_r(readline_list_history());
print_r(readline_user());
It is very useful to build real complex stuffs!
See how to catch and send POSIX signals.
PHP function readline()
If you want the interactive shell to process PHP commands, one example is phpsh which was apparently created at Facebook, but it is written in Python.
I know the questioner didn't want the second option, but for those that wanted the second option as I did, in addition to phpsh, PHP also has its own shell:
Just run php -a.
Check out Sheldon.
It's pretty easy to get started. It includes Symfony 2 and Zend Framework libraries that do a lot of the basic console I/O work and gives you a higher-level abstraction built around command objects (with regex routes) and Contexts (which hold immutable state).
One of the things I love is that "out of the box", your application can run as either an interactive shell, or as a standard script that you can run from the command line, specify a command, pass any arguments, and when the command is finished the application exits.
I have a code something like this:
$file = fopen( "debug.txt", "w" );
$command = "myExe.exe param0 param1";
fprintf( $file, "starting\r\n" );
fflush( $file );
system( $command );
fprintf( $file, "the end...\r\n" );
fflush( $file );
It prints "starting" but not "the end...". The system() function hangs.
The myExe.exe is an applicatication written in C++, which actually terminates; i.e. the main function of myExe ends with a code like this:
FILE* f = fopen( "test.txt", "w" );
fclose(f);
return 0;
test.txt is created, which means "myExe.exe" works and finishes normally.
That problem does not occur each time we call the php file; sometimes hangs, sometimes works...
Any help&idea will be appriciated. Thanks in advance.
info;
OS: win xp
php server: wamp server 2.0
edit: my problem is not about my debug files. It is about system() or exec() functions. I can remove all other lines.
my php script works well for about 4/5 tries. After system() called, i call some sql functions but when system() hangs, my page will give a fatal error.
There is a known bug in php on windows (http://bugs.php.net/bug.php?id=44942).
There is a workaround you may want to try, close the session (call session_write_close() ) before calling the exec function.
Try using an sprintf to print the formatted text to a string, then a write, like so:
$file = fopen( "debug.txt", "w" );
$command = "myExe.exe param0 param1";
$startStr = sprintf( "starting\r\n" );
fwrite($file, $startStr);
fflush( $file );
system( $command );
$endStr = sprintf( "the end...\r\n" );
fwrite($file, $endStr);
fflush( $file );
Or, if you're not using any formatted strings (which in this case it doesn't look like you are), get rid of the sprintfs and just use write.
I would recommend you download/buy something like phpDesigner or RapidPHP so you can step through the logic of the program and see what exactly is going on. Nothing jumps out at me for being wrong with the program but if there is, either of the above programs will find it and display it to you in red.
You really do not need the "\r\n" unless you just like double spacing things. Just the "\n" should work fine.
Also, have you tried the "php -l " command yet to check for errors? It might turn up something.
Last, but not least, there are other commands in PHP to run programs externally - have you tried the other commands yet?
Just some thoughts. :-)
PS: I just had another thought: What are param0 and param1? If they contain special characters - that might influence what is happening with the system command.
PPS: AH! I may have a partial answer. The "return 0" line might be the culprit. Try changing it to "exit( 0 );" instead. The return statement is not the same as exit. It tries to return to the calling program and there is none. However, the system might get confused and think it should return to the PHP script (since all a return command does is a RET which causes the JSR from the system command to try to catch the RET. By replacing it with an exit command you are telling the system command you are through with your program. The system command will then do its own RET command back to PHP. If that makes sense. Basically, you are doing a double RET with the return command and you are also pushing the zero(0) status code onto the stack. Since the system returns its own status normally (via the exit command) what might be happening is that the null (0) is being interpreted as a stop command to the system command. IE: The zero gets popped onto the system stack, the RET is generated, the system pops off the RET leaving the zero(0 or null) byte which it isn't expecting and that freezes the system command. Again, the answer would be to switch to using "exit( 0 );" rather than the return command. Just a guess but I think that I ran into this years ago when I was doing Perl and the answer then was to use exit instead of return. So I'm figuring with PHP it might be the same problem. (Had to think about this for a while before I remembered it.)
I have a feeling, yes just a feeling, that there are open handles in your process preventing it from exiting. Most of the time when this happens it the STDIN and STDOUT handles. Did you check to see if fclose() in your C++ application succeeded?
Download:
http://technet.microsoft.com/en-us/sysinternals/bb896653
Use it to see how many handles are open for myEXE.exe when it hangs.
Did you happen to greatly simplify your myEXE.exe for the purposes of SO and missed something?