PHP proc_open() pipes communication - php

The context is the following:
I'm using a Raspberry Pi with PHP5 and Apache installed on it and it's connected to a LED display.
There are a few executables on the Pi to make this LED display works.
I want my php script to fetch datas from the web with some APIs and display the result on the LED.
So, the display works fine. I have installed a C-based program in the the /var/www/ and here is an example
on /var/www/: sudo ./text-example -f fonts/5x8.bdf -r 16
(-f for the font used, -r for the number of rows of my LED)
When you execute this, you can write some text in the shell and it will display it on the LED.
So I made a simple test.php script with the following: $res = shell_exec('sudo ./test-example -f fonts/5x8.bdf -r 16'); and it works too. I can enter messages in the STDIN.
A little further, now I need to enter the text dynamically so I did a proc_open() in a proc.php:
<?php
$desc = array(0=>array("pipe", "r"), 1=>array("pipe", "w"));
$cwd = '/var/www/';
$process = proc_open('php test.php', $desc, $pipes, $cwd, NULL);
if (is_resource($process)) {
fwrite($pipes[0], 'hello');
fclose($pipes[0]);
}
?>
So, now I run in the shell: php proc.php. As soon as I define a $desc with pipe, the programm will execute, and then stop. The LED display is not displaying anything. If I remove the $desc variable and remove the pipes things (fwrite, fclose), I can enter text in the shell and it will execute properly as if it was test.php. I don't understand why it won't let me STDIN with fwrite and why the php is interrupted with theses pipes.

Related

unable to execute python script from php

I want to execute Python script from PHP file. I am able to execute simple python script like:
print("Hello World")
but when I want to execute following script, nothing happens
from pydub import AudioSegment
AudioSegment.converter = "/usr/bin/ffmpeg"
sound = AudioSegment.from_file("/var/www/dev.com/public_html/track.mp3")
sound.export("/var/www/dev.com/public_html/test.mp3", format="mp3", bitrate="96k")
and same script works fine when I execute it from terminal. here is my php script:
$output = shell_exec("/usr/bin/python /var/www/dev.com/public_html/index.py");
echo $output;
I have also tried following method but no luck:
$output = array();
$output = passthru("/usr/bin/python /var/www/dev.com/public_html/index.py");
print_r($output);
please help me
PHP's passthru function does not have the elegant method for which you may be searching of passing environment variables. If you must use passthru, then export your variables directly in the command:
passthru("SOMEVAR=$yourVar PATH=$newPATH ... /path/to/executable $arg1 $arg2 ...")
If you are inclined toward shell_exec, you may appreciate putenv for the slightly cleaner interface:
putenv("SOMEVAR=$yourVar");
putenv("PATH=$newPATH");
echo shell_exec("/path/to/executable $arg1 $arg2 ...");
If you are open to a more robust (if tedious) approach, consider proc_open:
$cmd = "/path/to/executable arg1 arg2 ..."
# Files 0, 1, 2 are the standard "stdin", "stdout", and "stderr"; For details
# read the PHP docs on proc_open. The key here is to give the child process a
# pipe to write to, and from which we will read and handle the "passthru"
# ourselves
$fileDescriptors = array(
0 => ["pipe", "r"],
1 => ["pipe", "w"],
2 => ["pipe", "w"]
);
$cwd = '/tmp';
$env = [
'PATH' => $newPATH,
'SOMEVAR' => $someVar,
...
];
# "pHandle" = "Process handle". Note that $pipes is new here, and will be
# given back to us
$pHandle = proc_open($cmd, $fileDescriptors, $pipes, $cwd, $env);
# crucial: did proc_open work?
if ( is_resource( $pHandle ) ) {
# $pipes is now valid
$pstdout = $pipes[ 1 ];
# Hey, whaddya know? PHP has just what we need...
fpassthru( $pstdout );
# Whenever you proc_open, you must also proc_close. Just don't
# forget to close any open file handles
fclose( $pipes[0] );
fclose( $pipes[1] );
fclose( $pipes[2] );
proc_close( $pHandle );
}
Acc to your reply, as you want to execute the python script from PHP
I was able to execute it using the following code
$command = escapeshellcmd('/var/www/yourscript.py');
$output = shell_exec($command);
echo $output;
Please use the above PHP code with the same python script.
Try to run the python script as a GCI script first to make sure it is working and set the permissions to public directory and script as I mentioned before
===================old ans============================
From what you asked, I guess this is what you are trying to do is that you are trying to run it as a CGI script like http://localhost/yourscript.py
And why are you using PHP to execute python script when you can run it directly as a CGI script?
here is what you need to do to make it work like a web page:
enable python CGI in apache ( or in the web server you are using ).
put the script in CGI configured directory
add proper code to your script to make it work as a CGI script
#!/usr/local/bin/python
from pydub import AudioSegment
AudioSegment.converter = "/usr/local/bin/ffmpeg"
sound = AudioSegment.from_file("/var/www/dev.com/public_html/track.mp3")
sound.export("/var/www/dev.com/public_html/test.mp3", format="mp3", bitrate="96k")
print "Content-type: text/html"
print
print ""
print ""
print ""
print "Done/ you can perform some conditions and print useful info here"
print ""
Give permissions to the script and make the public directory writable
Access the script http://localhost/your-path-to-script.py
I was able to run this properly.
let me know if that's not your case if you want something else
In my case, I did this code.
<?php
chdir('/home/pythontest') ; // python code dir
$commandline="/usr/bin/python3 test.py parameter" ;
exec($commandline, $output, $error) ;
echo $output ;
?>
If you need to set some environments for python, add environment vars like this.
$commmandline="LANG=en_US.utf8 LC_ALL=en_US.utf8 /usr/bin/python3 ..." ;
and check the httpd log.
Check this:
The apache user has to be in sudoers file, better you don't give sudo to apache instead give apache (www-data) user right to run your python program
put first line in your python script: #!/usr/bin/env python so the script knows which program to open it with..
then,
change group:
chgrp www-data /path/to/python-script.py
make it executabe:
chmod +x /path/to/python-script.py
then try it:
shell_exec("/path/to/python-script.py");
I hope this will work! :)
You can also exec ffmpeg directly without python:
$output = shell_exec("/usr/bin/ffmpeg -i in.mp3 -b:a 96k out.mp3");
echo $output;
ffmpeg docs
Answered in 2022.
In php 8.0 and above the following method worked. Above answers are very useful but i am compiling few extra steps here.
PHP Code.
$output = shell_exec("python3 /var/www/python/test.py");
print_r($output);
exec('python3 --version 2>&1', $output);
var_dump($output);
Trying both shell_exe and exec
Make sure the python file has executable permission and added to www-data group (if its ubuntu/debian systems) . sudo chmod +x test.py and sudo chgrp www-data test.py
Make sure the php.ini has disabled_functions line commented or empty.
sudo vim sudo vim /etc/php/8.0/cli/php.ini
sudo vim sudo vim /etc/php/8.0/apache2/php.ini
For both.
I compiled a simple video to make sure others dont spend more time figuring out the problem. https://youtu.be/t-f6b71jyoM

Open vim from PHP like git

How do i open vim from a PHP file to edit some other file like git when you run "git commit" without the -m flag?
I've tried this solution Open Vim From PHP CLI
from-php-cli but it gets me some IO error with vim :
Vim: Warning: Output is not to a terminal
Vim: Warning: Input is not from a termin?
is there other way to do this? probably with bash or something else?
Vim is an interactive editor. The error you are getting ("Output is not to a terminal") is a precise description of the problem. You can't control Vim from a PHP script.
If you need to pass text, you should use alternative approaches like the aforementioned -m flag or STDIN.
I was able to do it using the proc_open method with one of the solutions from Open Vim From PHP CLI and a cycle that constantly checks if the process is still running. Once you finish editing it continues running the script.
$descriptors = array(
array('file', '/dev/tty', 'r'),
array('file', '/dev/tty', 'w'),
array('file', '/dev/tty', 'w')
);
$process = proc_open($_SERVER['EDITOR']. $filename, $descriptors, $pipes);
//if(is_resource($process))
while(true){
if (proc_get_status($process)['running']==FALSE){
break;
}
}
It's not very elegant but it does the job :)
PS:I'm sorry for the bad English >.<
So you want to execute a bash script with PHP?
Take a look at:
shell_exec()
exec()
http://php.net/manual/de/function.shell-exec.php
http://php.net/manual/de/function.exec.php
The first one will return data from executed command, if you do a cat file.txt you will end up with a string which contains the content of file.txt
If you use exec it will not return std output, but will return true/false if the given command was successful.
You can now write a simple bash script which does manipulate text and then execute it via PHP.

Inject input into process connected to standard input (interactive console)

We have a tool which executes the PHP interactive shell like this:
$descriptorSpec = array(
0 => STDIN,
1 => STDOUT,
2 => STDERR
);
$prependFile = __DIR__ . '/../../../../../res/dev/console_auto_prepend.php';
$exec = 'php -a -d auto_prepend_file=' . escapeshellarg($prependFile);
$pipes = array();
proc_open($exec, $descriptorSpec, $pipes);
The trick with auto_prepend_file unfortunately causes issues with autoloading on PHP 5.3. We found out that everyting works well when we include the file inside the interactive shell:
$ php -a
Interactive shell
php > include "myproject/res/dev/console_auto_prepend.php";
Autoloader initialized.
What we want to do is the following:
execute php interactive shell via proc_open
send the include line to the interactive shell
hand over the controll to the user input
Is there any way to do this?
Untested idea:
Created a new input pipe
Open the PHP process (php -a) with that input pipe, stdout and stderr could be connected to the system pipes
Inject the include command (write to the input pipe)
In a loop read from the STDIN and write to our new input pipe (which is connected to the php -a)
The project ended up in using a custom PHP shell (psysh)

PHP exec in background using & is not working

I am using this code on Ubuntu 13.04,
$cmd = "sleep 20 &> /dev/null &";
exec($cmd, $output);
Although it actually sits there for 20 seconds and waits :/ usually it works fine when using & to send a process to the background, but on this machine php just won't do it :/
What could be causing this??
Try
<?PHP
$cmd = '/bin/sleep';
$args = array('20');
$pid=pcntl_fork();
if($pid==0)
{
posix_setsid();
pcntl_exec($cmd,$args,$_ENV);
// child becomes the standalone detached process
}
echo "DONE\n";
I tested it for it works.
Here you first fork the php process and then exceute your task.
Or if the pcntl module is not availabil use:
<?PHP
$cmd = "sleep 20 &> /dev/null &";
exec('/bin/bash -c "' . addslashes($cmd) . '"');
The REASON this doesn't work is that exec() executes the string you're passing into it. Since & is interpreted by the shell as "execute in the background", but you don't execute a shell in your exec call, the & is just passed along with 20 to the /bin/sleep executable - which probably just ignores that.
The same applies to the redirection of output, since that is also parsed by the shell, not in exec.
So, you either need to find a way to fork your process (as described above), or a way to run the subprocess as a shell.
My workaround to do this on ubuntu 13.04 with Apache2 and any version of PHP:
libssh2-php, I just used nohup $cmd & inside a local SSH session using PHP and it ran it just fine the background, of course this requires putting certain security protocols in place, such as enabling SSH access for the webserver user, so it would have exec-like permissions then only allowing localhost to login to the webserver ssh account.

What is linux equivalent of running a .bat file on windows from PHP using system()

I have a PHP script that runs a .bat file on my windows machine using
$result = system("cmd /C nameOfBatchFile.bat");
This sets some environmental variables and is used to call Amazon EC2 API from the command line.
How do I do the same from a Linux server? I have renamed my .bat file to a shell (.sh) and changed the script to use 'export' when setting env vars. I have tested by running the code from a putty terminal and it does what it should. So I know the commands in the script are good. How do I run this from PHP? I have tried running the same command as above with the new filename and I don't get any errors, or file not found etc but it doesn't appear to work.
Where do I start trying to solve this?
---------------------------------- UPDATE -------------------------------
Here is the PHP script that calls the shell file -
function startAmazonInstance() {
$IPaddress = "1.2.3.4"
$resultBatTemp = system("/cmd /C ec2/ec2_commands.sh");
$resultBat = (string)$resultBatTemp;
$instanceId = substr($resultBat, 9, 10);
$thefile = "ec2/allocate_address_template.txt";
// Open the text file with the text to make the new shell file file
$openedfileTemp = fopen($thefile, "r");
contents = fread($openedfileTemp, filesize($thefile));
$towrite = $contents . "ec2-associate-address -i " . $instanceId . " " . $IPaddress;
$thefileSave = "ec2/allocate_address.sh";
$openedfile = fopen($thefileSave, "w");
fwrite($openedfile, $towrite);
fclose($openedfile);
fclose($openedfileTemp);
system("cmd /C ec2/mediaplug_allocate_address_bytemark.sh");
}
And here is the .sh file - ec2_commands.sh
#!/bin/bash
export EC2_PRIVATE_KEY=$HOME/.ec2/privateKey.pem
export EC2_CERT=$HOME/.ec2/Certificate.pem
export EC2_HOME=$HOME/.ec2/ec2-api-tools-1.3-51254
export PATH=$PATH:$EC2_HOME/bin
export JAVA_HOME=$HOME/libs/java/jre1.6.0_20
ec2-run-instances -K $HOME/.ec2/privateKey.pem -C $HOME/.ec2/Certificate.pem ami-###### -f $HOME/.ec2/aws.properties
I have been able to run this file from the command line so I know that the commands work ok. When I had this working on windows there would be a delay as the instance started up and I could echo the results to the screen. Now there is no delay as if nothing is happening.
Put a hash-bang on the first line of your shell script.
#!/bin/bash
Then give it the executable flag.
$ chmod a+x yourshellscript
You can then call it from PHP with system.
$result = system("yourshellscript");
$result = system("/bin/sh /path/to/shellfile.sh");
Is script executable? If not, make it so:
$ chmod a+x script.sh # shell
system ("/path/to/script.sh"); // PHP
or launch it via interpreter:
system("sh /path/to/script.sh"); // PHP
Is interpreter specified in shell script (ie. #!/bin/sh line)?
have you tried shell_exec() ?

Categories