I have a php script that leads up to running another expect script by passing it arguments.
$output = shell_exec("expect login_script.tcl '$user' '$host' '$port' '$password'");
Using shell_exec doesn't work as the script gets run in the background or 'within' the php script. I need it to run in the foreground, allowing user interactivity. Is there an elegant way to do this. Already it is getting messy by having to use different scripting languages. I tried wrapping the two scripts with a shell script that called the php script, assigned output the result as a variable (which was a command) and then ran sh on that. However I have the same problem again where the scripts are run in the background and any user interactivity creates a halt/freeze. Its ok in this situation if php 'quits' out when calling shell exec. Ie. php stops and expect gets run as if you called it. (the same as if i just copied the command that is output and pasted it into the terminal).
Update
I am having much more luck with the following command in php:
shell_exec("gnome-terminal -e 'bash -c \"expect ~/commands/login_script.tcl; exec bash\"' &");
However, can this be improved in order to not close the shell immediately after the secondary script (login_script) is finished?
Further Update
From reading the answers I think I need to clarify things as it looks like people are assuming a 'more complicated' issue.
the two processes do not need to communicate with each other, I should probably not have put the $output = shell_exec in the example and just shell_exec on its own as I believe this has led to the confusion.
The php script needs to only initiate the expect script with some cli parameters, e.g. my-script 'param1' 'param2' and can be thought of as completely 'asynchronous'. This is much like the behaviour of launcher programs like 'launchy' or 'synapse' they can launch other programs but need not affect them. Nor do they wait for the secondary program to quit/finish.
I made the mistake of saying 'shell_exec' doesn't work for me. What I should have said was that 'I have so far not succeeded with using shell_exec', but shell_exec("gnome-terminal -e 'bash -c \"expect ~/commands/login_script.tcl; exec bash\"' &"); is 'working' but still trying to find the right quote combination to allow passing arguments to the expect script.
Task managing is an interesting but difficult job.
Because your user can move during a task (and leads it to an unexpected result, such as session freezes, or an incomplete work from the process), you need to execute it in background. If you need to interact between your user and your process, you'll need to create a way to communicate.
The easiest way (I think) is to use a file, shared between your user session and the task.
If you have a lot of users simultaneously and communicates a lot between user and processes, you can mount a partition in memory to optimize the read/write operations.
In your fstab, a line like :
tmpfs /memory tmpfs defaults,uid=www-data,gid=www-data,size=128M 0 0
Or, in a script, you could do :
#!/bin/sh
mkfs -t ext2 -q /dev/ram1 65536
[ ! -d /memory ] && mkdir -p /memory
mount /dev/ram1 /memory
chmod -R 777 /memory
You'll need to take care of a lot of things :
file access (to avoid concurrency between your webapp and your processes)
time (to avoid zombies or useless long-running scripts)
security (such operations must be carefully designed)
resources management (to avoid that 10000 processes runs simuntaneouly)
...
I think what you're looking for is the proc_open() command. It gives you access to the stdin/stdout streams of the background process. You can pass your own stdin/stdout streams to the new process in the $descriptorSpec parameter, which will let your background process talk to the user.
Your 'foreground' application will have to wait around until the background process has died. I haven't actuallly done this with PHP, but I'm guessing you'll have to watch the $pipes to see when they get closed -- then you'll know the background process is finished and you can delete the process resource and continue on with whatever the foreground process needs to do.
In the end, I managed to get it working by by adding a third quotation mark type: ` (I believe it is called a 'tack'?) which allowed me to pass arguments to the next script from the first script
The command I needed in my php script was:
$command = `gnome-terminal -e 'bash -c "expect ~/commands/login_script.tcl \"$user\" \"$host\" \"$port\" \"$password\"; exec bash"' &`;
shell_exec($command);
It took a while to get all the quotes right as swapping the type of quotes around can lead to it not working.
Here is a video demonstrating the end result
Use:
pcntl_exec("command", array("parameter1", "parameter2"));
For example, I have a script that starts the mysql command using the parameters in the current php project that looks like:
pcntl_exec("/usr/bin/mysql", array(
"--user=".$params['user'],
"--password=".$params['password'],
"--host=".$params['host'],
$params['dbname']
));
This doesn't rely on gnome terminal or anything, it replaces PHP with the program you call.
You do need to know the full path of the command, which is a pain because it can vary by platform, but you can use the env command command which is available at /usr/bin/env on most systems to find the command for you. The above example above becomes:
pcntl_exec("/usr/bin/env", array(
"mysql",
"--user=".$params['user'],
"--password=".$params['password'],
"--host=".$params['host'],
$params['dbname']
));
Related
Currently I have a parser.php which loads an xml file and inserts new data from the xml file into a mysql database. How would I go about refreshing this php file every 30 seconds so my mysql table always has fresh data? I think I could use short-polling to do this, but I'm guessing this is not the most efficient of options.
Thanks in advance
This is a non-PHP solution which will require you to have shell (SSH) access in order to run the script, however you can also run it through PHP with exec() if you want to. Shared hosting environments might present a challenge for this approach but as long as you can execute scripts under your user credentials you should have no problems running it.
First you will need to create a bash script with the following content and save it (I'll use the name parser.sh for the purpose of this example). You can then adjust the timeout in the sleep 30 line if you want to.
#!/bin/sh
while true
do
php parser.php
sleep 30
done
In order to run the script you'll need to give it execute permissions.
chmod +x parser.sh
Now you can use the nohup command with the ampersand (&) argument to ensure that the script will run in the background even when a termination signal is sent after, lets say, closing the shell (SSH). The ampersand is important!
nohup ./parser.sh &
Now you can use top or ps aux | grep parser to ensure that the script is running. As I already said before you can also use PHP exec() to start the process but shell is still the preferred and most reliable way to do this.
If you want to stop the background process which executes your script then you'll simply have to kill it. Just use ps aux | grep parser to find out the PID of the parser process (its in the second column to the left) and use it with the kill command.
kill 4183
You need to use a cronjob, but crons jobs runs every 1 minute or more.
Another way is to make a "daemon".
Very basic example:
<?php
while(true) {
// check if 30 seconds has passed.
// then execute some function...
};
?>
Then you need to execute this in your terminal:
$ php script.php &
This link should help.
Greatings!
In a apcahe server i want to run a PHP scripts as cron which starts a php file in background and exits just after starting of the file and doesn't wait for the script to complete as that script will take around 60 minutes to complete.how this can be done?
You should know that there is no threads in PHP.
But you can execute programs and detach them easily if you're running on Unix/linux system.
$command = "/usr/bin/php '/path/to/your/php/to/execute.php'";
exec("{$command} > /dev/null 2>&1 & echo -n \$!");
May do the job. Let's explain a bit :
exec($command);
Executes /usr/bin/php '/path/to/your/php/to/execute.php' : your script is launched but Apache will awaits the end of the execution before executing next code.
> /dev/null
will redirect standard output (ie. your echo, print etc) to a virtual file (all outputs written in it are lost).
2>&1
will redirect error output to standard output, writting in the same virtual and non-existing file. This avoids having logs into your apache2/error.log for example.
&
is the most important thing in your case : it will detach your execution of $command : so exec() will immediatly release your php code execution.
echo -n \$!
will give PID of your detached execution as response : it will be returned by exec() and makes you able to work with it (such as, put this pid into a database and kill it after some time to avoid zombies).
You need to use "&" symbol to run program as background proccess.
$ php -f file.php &
Thats will run this command in background.
You may wright sh script
#!/bin/bash
php -f file.php &
And run this script from crontab.
This may not be the best solution to your specific problem. But for the record, there is Threads in PHP.
https://github.com/krakjoe/pthreads
I'm assuming you know how to use threads, this is very young code that I wrote myself, but if you have experience with threads and mutex and the like you should be able to solve your problem using this extension.
This is clearly a shameless plug of my own project, and if the user doesn't have the access required to install extensions then it won't help him, but many people find stackoverflow and it will solve other problems no doubt ...
I have a collection of bash and Perl scripts to
develop a directory structure desired for deployment on linux box
(optionally) export code from svn
build a package from this source
This is working well from terminal. Now my client requests a web interface to this process.
e.g "Create New Package" button on certain page will invoke above steps one by one and return the output to user as script echos, not when the whole scripts executes.
Is it possible to send instantaneous output from bash script to webpage or php script which has invoked it through program execution functions (system, exec, passthru ... or any thing else that suite this process flow) ?
What is elegant why to do this ?
What security precautions I should take while doing such thing (if possible)?
Edit
After some search I have found part of the solution but still not working :
$cmd = 'cat ./password.txt|sudo -S ./setup.sh ';
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("pipe", "w") // stderr is a pipe that the child will read from
);
flush();
$process = proc_open($cmd, $descriptorspec, $pipes, './', array());
echo "<pre>";
if (is_resource($process)) {
while ($s = fgets($pipes[1])) {
print "Message:".$s;
flush();
}
while ($s = fgets($pipes[2])) {
print "Error:".$s;
flush();
}
}
echo "</pre>";
output: (webpage)
Error:WARNING: Improper use of the sudo command could lead to data loss
Error:or the deletion of important system files. Please double-check your
Error:typing when using sudo. Type "man sudo" for more information.
Error:
Error:To proceed, enter your password, or type Ctrl-C to abort.
Error:
Error:Password:
Error:Sorry, try again.
Error:Password:
Error:Sorry, try again.
Error:Password:
Error:Sorry, try again.
Error:sudo: 3 incorrect password attempts**
First issue I am having now is to pass sudo passoword
help please !
I would use a kind of master / slave design. The slave would be your perl / bash script, just doing a job (packaging, compiling, exporting code or so), and feed a log entry.
The master would be your php process. So the principle is the following: the master and the slave share a communication channel, and communicate asynchronously from that channel.
You could imagine a database like:
create table tasks ( id INT primary key, status INT, argument VARCHAR(100));
You php page should switch user choice, and filter input:
switch ($_GET['action']) {
case 'export':
$argument = sanitize($_GET['arg']);
add_task('export', $argument);
break;
case '...':
// ...
}
and the add_task function could be something like:
function add_task($action, $arg)
{
return $db->add('tasks', array($action, NEW_TASK, $arg);
}
The slaves could be run via a cron job, and query the database, feeding the progression of the task.
The pro are:
independant systems, ease the evolution.
if a client gets disconnected, the job is never lost
easier to secure
The cons are:
a little more complicated at the beginning.
less reactive, because of the polling time of the slaves running (for instance if they run every 5 minutes)
less output than the direct output of the command
Notice that you can then implement xml-rpc like triggers to run the slaves, rather than using a message passing system.
The simplest approach is to use shell_exec for your purpose. It executes a command via shell and returns the complete output as a string, hence you can display it on your website.
If this doesn't suit your purpose, because maybe you want some responses while waiting for the command to finish, check out the other program execution functions available in php (hint: there are a few good comments on the manual pages).
Keep in mind, when evoking commandline scripts this way, generated output will have the file owner, group and permissions of your webserver (p.e. wwwrun or whatever). If parts of your deployment need a separate owner, group and/or file permissions, you have to manually set them either in your scripts or after invoking shell_exec (chmod, chown and chgrp can deal with this in php).
About security:
Alot of web-based applications put that kind of function into a separate installation directory, and kindly ask you to remove this directory after installing. I even remember some of them shouting at admins quite persistent unless it is removed. This is an easy way preventing this script being invoked by wrong hands at a wrong time. If your application might need it after installing, then you have to put it into an area where only authorized users have access to (p.e. admin area or something similar).
You can use the Comet web application model to do real time updating of the results page.
For the sudo problem, as a quick and dirty solution I'd use restricted set of commands that the web server can execute without password. Example (add in /etc/sudoers):
apache ALL=(ALL) NOPASSWD: /sbin/service myproject *
which would allow apache to run /sbin/service myproject stop, /sbin/service myproject start and so on.
Take a look at Jenkins, it does the web part nicely, you'll only have to add your scripts in the build.
A better solution would be, as suggested by Aif, to separate the logic. One daemon process waiting for tasks and a web application visualizing the results.
Always use escapeshellarg and escapeshellcmd when executing system commands via PHP for security. It would also be suggested to have the user within a chroot'd directory as limited as possible.
You seem to have solved the issue of getting stdout and stdin to be outputted to your webpage by using proc_open. Now the problem looks to be executing the script via sudo.
From a security perspective, having a PHP app run a script as root (via sudo) makes me cringe. Having the root password in password.txt is a pretty huge security hole.
What I would do (if possible) is to make whatever changes necessary so that setup.sh can be run by the unix user that is running Apache. (I'm assuming you're running PHP with Apache.) If setup.sh is going to be executed by the webserver, it should be able to run it without resorting to sudo.
If you really need to execute the script as a different user, you may check into suPHP, which is designed to run PHP scripts as a non-standard user.
Provide automated sudo rights to a specific user using the NOPASSWD option of /etc/sudoers then run the command with the prefix sudo -u THE_SUDO_USER to have the command execute as that user. This prevents the security hole of giving the entire apache user sudo rights, but also allows sudo to be executed on the script from within apache.
I have a large PHP application and I'm looking for a way to know which PHP script is running at a given moment. Something like when you run "top" on a Linux command line but for PHP.
Are you trying to do so from within the PHP application, or outside of it? If you're inside the PHP code, entering debug_print_backtrace(); at that point will show you the 'tree' of PHP files that were included to get you at that point.
If you're outside the PHP script, you can only see the one process that called the original PHP script (index.php or whatnot), unless the application spawns parallel threads as part of its execution.
If you're looking for this information at the system level, e.g. all php files running under any Apache child process, or even any PHP files in use by other apps, there is the lsof program (list open files), which will spit out by default ALL open files on the system (executables, sockets, fifos, .so's, etc...). You can grep the output for '.php' and get a pretty complete picture of what's in use at that moment.
This old post shows a way you can wrap your calls to php scripts and get a PID for each process.
Does PHP have threading?
$cmd = 'nohup nice -n 10 /usr/bin/php -c /path/to/php.ini -f /path/to/php/file.php action=generate var1_id=23 var2_id=35 gen_id=535 > /path/to/log/file.log & echo $!';
$pid = shell_exec($cmd);
I need to have a script execute (bash or perl or php, any will do) another command and then exit, while the other command still runs and exits on its own. I could schedule via at command, but was curious if there was a easier way.
#!/bin/sh
your_cmd &
echo "started your_cmd, now exiting!"
Similar constructs exists for perl and php, but in sh/bash its very easy to run another command in the background and proceed.
edit
A very good source for generic process manipulation are all the start scripts under /etc/init.d. They do all sorts of neat tricks such as keep track of pids, executing basic start/stop/restart commands etc.
To run a command in the background, you can append an '&' to the command.
If you need the program to last past your login session, you can use nohup.
See this similar stackoverflow discussion: how to run a command in the background ...
The usual way to run a command and have it keep running when you log out is to use nohup(1). nohup prevents the given command from receiving the HUP signal when the shell exits. You also need to run in the background with the ampersand (&) command suffix.
$ nohup some_command arg1 arg2 &
&?
#!/usr/bin/bash
# command1.sh: execute command2.sh and exit
command2.sh &
I'm not entirely sure if this is what you are looking for, but you can background a process executed in a shell by appending the ampersand (&) symbol as the last character of the command.
So if you have script, a.sh
and a.sh needs to spawn a seperate process, like say execute the script b.sh, you'd:
b.sh &
So long as you mentioned Perl:
fork || exec "ls";
...where "ls" is anything at all. Repeat for as many commands as you need to fire off.
Most answers are correct in showing..
mycmd &
camh's answer goes further to keep it alive with nohup.
Going further with advanced topics...
mycmd1 &
mycmd2 &
mycmd3 &
wait
"wait" will block processing until the backgrounded tasks are all completed. This can be useful if response times are significant such as for off-system data collection. It helps if you an be sure they will complete.
How do I subsequently foreground a process?
If it is your intent to foreground a process on a subsequent logon, look into screen or tmux.
screen -dmS MVS ./mvs
or (Minecraft example).
screen -dm java -Xmx4096M -Xms1024M -jar server.jar nogui
You can then re-attach to the terminal upon subsequent login.
screen -r
The login that launches these need not be interactive, you can use ssh remotely (plink, Ansible, etc.) to spawn these in a "drive by" manner.