How does the shell_exec work in php? when I disconect the browser connection to the server, will the shell_exec continue working?
The php process will be terminated when the client closes the connection unless you use ignore_user_abort(1);
Also, the process needs to send something to the client to check if he is still connected. A process that has no output may continue to run after the client disconnects.
To execute a command in the background and keep it running after the php process ends, use something like this:
exec($cmd.' > /dev/null &');
Related
I have 2 websites, hosted on 2 different servers. They are kind of interlinked. Sometimes I just do stuff on Website-1 and run a script on Website-2. Like I edited something on Website-1 and now I want to run a script on Website-2 to update accordingly on it's server.
Till now I am using following code on website 1.
$file = file_get_contents('Website-2/update.php');
But the problem with this is that my Website-1 server script stops running and wait for the file to return some data. And I don't wanna do anything with that data. I just wanted to run the script.
Is there a way where I can do this in a better way or tell PHP to move to next line of code.
If you want to call the second site without making your user wait for a response,
I would recommend using a message queue.
Site 1 request would put a message to the queue.
Cron job to check queue and run update on site 2 when message exists.
Common queues apps to look at:
[https://aws.amazon.com/sqs/?nc2=h_m1][1]
[https://beanstalkd.github.io/][2]
[https://www.iron.io/mq][3]
[1]: https://aws.amazon.com/sqs/?nc2=h_m1
[2]: https://beanstalkd.github.io/
[3]: https://www.iron.io/mq
What you're trying to achieve is called a web hook and should be implemented with proper authentication, so that not anybody can execute your scripts at any time and overload your server.
On server 2 you need to execute your script asynchronously via workers, threads, message queues or similar.
You can also run the asynchronous command on your server 1. There are many ways to achieve this. Here are some links with more on this.
(Async curl request in PHP)
(https://segment.com/blog/how-to-make-async-requests-in-php/)
Call your remote server as normal. But, In the PHP script you normally call, Take all the functionality and put it in a third script. Then from the old script call the new one with (on Linux)
exec('php -f "{path to new script}.php" $args > /dev/null &');
The & at the end makes this a background or non-blocking call. Because you call it from the remote sever you don't have to change anything on the calling server. The php -f runs a php file. The > /dev/null sends the output from that file to the garbage.
On windows you can use COM and WScript.Shell to do the same thing
$WshShell = new \COM('WScript.Shell');
$oExec = $WshShell->Run('cmd /C php {path to new script}.php', 0, false);
You may want to use escapeshellarg on the filename and any arguments supplied.
So it will look like this
Server1 calls Server2
Script that was called (on Server2) runs exec and kicks off a background job (Server2) then exits
Server1 continues as normal
Server2 continues the background process
So using your example instead of calling:
file_get_contents('Website-2/update.php');
You will call
file_get_contents('Website-2/update_kickstart.php');
In update_kickstart.php put this code
<?php
exec('php -f "{path}update.php" > /dev/null &');
Which will run update.php as a separate background (non-blocking) call. Because it's non-blocking update_kickstart.php will finish and return to searver1 which can go about it's business and update.php will run on server2 independantly
Simple...
The last note is that file_get_contents is a poor choice. I would use SSH and probably PHPSecLib2.0 to connect to server2 and run the exec command directly with a user that has access only to that file(Chroot it or something similar). As it is anyone can call that file and run it. With it behind a SSH login it's protected, with it Chrooted that "special" user can only run that one file.
This might be a very stupid question so please bear with me.
I have a a php script that makes API calls to Shopify.
The entire point of this php script is to print out statements for each customer.
Now it has to run through about 200 customers.
This entire process takes about 15 minutes.
Ordinarily this runs on a monthly basis with a cron job.
But I need to be able to run it manually as well. I just want the page to execute and do everything in the background with my browser or internet connection playing NO role as to whether the complete execution completes.
The cron job runs header_php.php?run=monthly
Is there anyway I can run it manually, make sure it gets a 200 response from the page, and then close my browser tab and ensure that apache does the rest?
I would be executing it via an AJAX call as well.
Another thing, once each statement is done being processed, the script outputs it to pdf and emails it to the customer. So there's no feedback required from the page when it runs.
Easily doable with simple HTTP headers.
Start output buffering
Output the response, if any
Send Content-length and Connection: close headers
Flush and end output buffers
The browser receives HTTP response
Continue time consuming processing
This SO anwer nails it (the comments are helpful as well).
You can call your script with other script that runs in background the job.
shell_exec('nohup /usr/bin/php /dir/to/your/script.php > /dev/null 2>/dev/null &');
Then you don't need to wait to finish the job
on linux
<?php
exec(''.$command.' > /dev/null 2>&1 &');
?>
on windows
<?php
$shell = new COM("WScript.Shell");
$shell->run($command, 0, false);
?>
where command would be something like
php -f $path/to/filename
if you put that in a page, you can then call it whenever you want and it will spawn a thread that will call apache, but not require the browser to wait for any response.
How can I run a php file IN BACKGROUND after submitting a form. The loading has to happen in background since it usually takes a very long time.
Basically it's just like running a cronjob, except I want to trigger it manually and with my browser.
There are several possible ways to do this.
Try setting ignore_user_abort to TRUE in your script.
If changed to TRUE scripts will not be terminated after a client has aborted their connection.
Take a look at popen() and pclose(). You can do something like this:
pclose(popen("start php /path/to/myscript.php", "r"));
You can kick off a separate PHP process with a system() or exec() call. Something like this:
system('php /path/to/myscript.php >/dev/null 2>&1 &');
Start the request using AJAX. The browser will continue running while waiting for a response. You can even show a popup or some information when the request is finished, although you don't have to.
I have a PHP site that performs Cron's that are triggered during client executions instead of a Cron manager. One of the Cron's that are performed takes a few seconds to execute, and it keeps the connection between the Client and the Server open until it is complete. Although I know I can set up a Cron to be fired from the Server instead of during Client runs, I would like to know if it is possible without following that format.
So, can the PHP script send a command to Apache (or whatever server it is hosted on) to close the connection between the Client and the Server, but continue to functions (so, without exiting)?
This works on Apache (and apparently not on IIS with FastCGI)
<?php
ignore_user_abort(true); // make sure PHP doesn't stop when the connection closes
// fire and forget - do lots of stuff so the connection actually closes
header("Content-Length: 0");
header("Connection: Close");
flush();
session_write_close(); // if you have a session
do_processing();
// don't forget to `set_time_limit` if your process takes a while
You can use shell to call the PHP binary... example:
shell("php -f /path/to/cronfile.php > /dev/null 2>/dev/null &"); which will run and not wait for a return.
See Asynchronous shell exec in PHP
Typically There is two forms of execution.
Client sided:
The client will remain on the page and the page will continue to process the commands given until completion.
Server Sided:
The client will navigate to a page & You make a switch in the database:
UPDATE Table SET PendinCron=1 WHERE IdentiferCol=$IdentiferData
Then you will have a Cronjob being run at X interval and will only process when the PendinCron is equal to one, if it is not. The Cron will not execute the required task.
I have a working php script using shell_exec to execute an external program that take about 30 seconds to complete.
Problem is that if an user close the browser or the connection is closed for some reason the program executed with shell_exec continue to run for nothing, since it's output can't be sent to the user anymore.
Is there a way to kill this process as soon as the connection is closed?
Thank you for your help.
Finally I've solved it!
I've used the PHP function connection_aborted() to check if the client is disconnected.
http://us2.php.net/manual/en/function.connection-aborted.php
The algorithm is the following (pseudocode)
shell_exec("script");//script is a shell script that launch the program in another thread thus this return immediately
$task_completed=false;
while(!$task_completed){
if(connection_aborted()==1){
kill_the_process();//this will kill the running process launched by script
die();
}
$task_completed=...;//true if the task completed
sleep(1);
}
You could make a manager that runs/executes/stops the running php scripts. This script would run constantly -maybe as daemon- and check the status of the script/process, the user status and close the script if the user is gone. I think you could do this well with Sockets.
How to Use Sockets in JavaScript\HTML?
http://php.net/manual/en/book.sockets.php
you can use to get the list of all running process
$res = shell_exec('ps -x');
$res = explode("\n",$res);
print_r($res);
and use this to kill process with given ProcessID
shell_exec('kill -KILL ProcessID');