So, I'm working on a time-sensitive website in PHP on my CentOS server. I have a random time selected in the future, within 24 hours of the present. At that point, I need a PHP file to execute, and a new date to be selected and the same file to be opened. How is this possible to accomplish? I looked briefly at cronjobs, but I couldn't find a way to make them open at a specific, random, time.
You can use at command, run your PHP file and in the end, register make another call to at for the next time. Something like this
<?php
// your PHP code in here, and then find out when is the next call time
$time = date('H:i', intval($time)); // or another good way to make sure time value is safe to use as a shell argument, like using escapeshellarg()
$run_me = "/usr/bin/env php " . __FILE__;
exec("echo '$run_me' | at '$time'");
One possible workaround is to run a script from a cron job, say, every 10 minutes. On the top of the script, check a specific file which is supposed to contain a timestamp. If the current time is greater than the value from the file, do the job, and write the new timestamp value into this file.
$time_to_run = intval(file_get_contents('my.timestamp'));
if(time() >= $time_to_run) {
do stuff
file_put_contents(time() + random value, 'my.timestamp');
}
If you need more granularity, a better option would be to run it as a daemon (see advices here) and just loop forever (probably with some sleep() inside) until the time comes.
Related
I have a PHP script that read and export CSV to a database. At the beginning of each execution, the script get a customer name with $_POST. It runs around 7 minutes to send 120k row. Nevertheless, my host allow PHP scripts to run up to 165 seconds.
My idea was then to refresh the page before the 165s and start the export again, at the row it ended. I've succedeed to refresh the page, but I struggle to conserve the variable saving the row position at which the script ended in order to use it after the refresh.
I could use $_POST or $_SESSION, but my script may run several time at the same moment, exporting a different CSV each run. I'm afraid that changing these super global variable from scripts that may run at the same time make them collide, and change their value when I don't want to.
First : is the above affirmation true?
Then if it is, how can I store the number of row the script ended before refreshing the page. I though about creating a file, putting the informations inside and then read it. That may look like this :
customer_name : Jon
row_ended : 10584
customer_name : Jane
row_ended : 11564
But isn't there a more easier and efficient solution?
You can create a run ID and save it on the session.
Ex.
session_start();
$_SESSION['run']['id'] = 1; // or some unique ID
$_SESSION['run']['user'] = 'jon';
$_SESSION['run']['lastRow']= 0;
$startTime = time() + 160; // total secs
if($starTime > time() ){
// time of 160 passed redirect to same page.
$_SESSION['run']['lastRow']= 100000;
header("location: page.php");
exit;
}
But this will not solve the problem, can be be a redirect hell
You can try to increase the max execution time at runtime.
ini_set('max_execution_time',0); //will run forever
or the best solution run it as a shell command with max_execition_time = 0
users may navigate away the page if it takes too long.
I've been completely unsuccessful finding an answer to this question. Hopefully someone here can help.
I have a PHP script (a WordPress template, to be specific) that automatically imports and processes images when a user hits it. The problem is that the image processing takes up a lot of memory, particularly if multiple users are accessing the template at the same time and initiating the image processing. My server crashed multiple times because of this.
My solution to this was to not execute the image-processing function if it was already running. Before the function started running, I would check a database entry named image_import_running to see if it was set to false. If it was, the function then ran. The very first thing the function did was set image_import_running to true. Then, after it was all finished, I set it back to false.
It worked great -- in theory. The site hasn't crashed since, I can tell you that. But there are two major problems with it:
If the user closes the page while it's loading, the script never finishes processing the images and therefore never sets image_import_running back to false. The template will never process images again until it's manually set to false.
If the script times out while it's processing images -- and that's a strong possibility if there are many images in the queue -- you have essentially the same problem as No. 1: the script never gets to the point where it sets image_import_running back to false.
To handle No. 1 (the first one of the two problems I realized), I added ignore_user_abort(true) to the script. Did it work? I don't know, because No. 2 is still an issue. That's where I'm stumped.
If I could ask the server whether the script was running or not, I could do something like this:
if($import_running && $script_not_running) {
$import_running = false;
}
But how do I set that $script_not_running variable? Beats me.
I've shared this entire story with you just in case you have some other brilliant solution.
Try using
ignore_user_abort(true); it will continue to run even if the person leaves and closes the browser.
you might also want to put a number instead of true false in the db record and set a maximum number of processes that can run together
As others have suggested, it would be best to move the image processing out of the request itself.
As an interim "fix", store a timestamp alongside image_import_running when a processing job begins (e.g., image_import_commenced). This is a very crude mechanism, but if you know the maximum time that a job can run before timing out, the script can check whether that period of time has elapsed.
e.g., if image_import_running is still true but the current time is more than 10 minutes since image_import_commenced, run the processing anyway.
What about setting a transient with an expiry time that would throttle the operation?
if(!get_transient( 'import_running' )) {
set_transient( 'import_running', true, 30 ); // set a 30 second transient on the import.
run_the_import_function();
}
I would rather store the job into database flagging it pending and set a cron job to execute the processing one job at a time.
For Me i use just this simple idea with a text document. for example run.txt file
in the top script use :
if((file_get_contents('run.txt') != 'run'){ // here the script will work
$file = fopen('run.txt', 'w+');
fwrite($file, 'run');
fclose('run.txt');
}else{
exit(); // if it find 'run' in run.txt the script will stop
}
And add this in the end of your script file
$file = fopen('run.txt', 'w+');
fwrite($file, ''); //will delete run word for the next try ;)
fclose('run.txt');
That will check if script already work by checking runt.txt contents
if run word exist in run.txt it will not run
Running a cron would definitively be a better solution. Idea to store url in a table is a good one.
To answer to the original question, you may run a ps auxwww command with exec (Check this page: How to get list of running php scripts using PHP exec()? ) and move your function in a separated php file.
exec("ps auxwww|grep myfunction.php|grep -v grep", $output);
Just add following on the top of your script.
<?php
// Ensures single instance of script run at a time.
$fileName = basename(__FILE__);
$output = shell_exec("ps -ef | grep -v grep | grep $fileName | wc -l");
//echo $output;
if ($output > 2)
{
echo "Already running - $fileName\n";
exit;
}
// Your php script code.
?>
I have a php file that returns html based on certain parameters, but it also saves this output in a separate directory (basically a custom made caching process).
Now I want to build a separate php file that automatically updates the cache based on array of known possible parameters.
So I want to "load" or "run" rather than "include" the file several times with the different parameters so that it will save the results in the cache folder.
Is there a php function that will allow me to simply load this other file and perhaps tell me when it is done? If not, do I need to use ajax for something like this or maybe PHP's curl library??
At the present I was thinking about something along the following lines:
<?php
$parameters = array("option1", "option2", "option3");
//loop through parameters and save to cache folder
foreach ($parameters as $parameter){
//get start time to calculate process time
$time_start = microtime(true);
sleep(1);
//I wish there was some function called run or load similar to jquery's 'load'
run("displayindexsearch.php?p=$parameter");
//return total time that it took to run the script and save to cache
$time_end = microtime(true);
$time = $time_end - $time_start;
echo "Process Time: {$time} seconds";
}
?>
why don't you include the file, but create functions for the things you want to do inside the file. That way, at the time when you want to run, you simply call the function. This seems to be the correct way to do what you are trying to do if I understand it correctly.
The best solution I found is to use:
file_get_contents($url)
So where the questions looks for a replacement for run, I substitute file_get_contents($url).
Note that I was getting errors when I used a relative path here. I only had success when I used http://localhost/displayindexsearch.php?p=parameter etc.
Please take a look at this question.
Launch php file from php as background process without exec()
It might be helping for you.
I am running a script which constantly works over my Database. How ever It is necessary to restart the script once an hour. Obviously I can't do that automatically. I don't want to use daemon, its too complex for me right now. Easier solution is to use cron job but biggest drawback is, it won't stop the last script. Script runs in infinite while(true) loop
However is that possible if I make function in a script, lets say
function exitScript()
{
exit;
}
And then on Cron job if i do something like
php /home/Path/public_html/webservice/myScript.php exitScript and then
php /home/Path/public_html/webservice/myScript.php
What will be the format and How can I run both one by one using cron job or make another PHP who does so?
I need advice.
Here is a little trick easy to made which you can use..
1st set you cron jobs to run on each hour.
* */1 ..... cronjob.php
2nd At start of your script define 1 constant with time:
define('SCRIPT_START_TIME', time());
3rd At your exit script set up a condition check to exit if 59 minutes are passed from this constant to current time.. :)
function exitScript()
{
if((time() - SCRIPT_START_TIME) > 59*60){
exit();
}
}
4th at each while LOOP start the exit script .
I have php scripts that call perl scripts to do various things and sometimes I get it where it just goes on and on without getting a response back, this is based on the variable that is being passed to the perl script and I am doing a lot of different ones in succession so I can't get really debug it directly since I don't have a response from perl...
I would really like to just be able to set a php function or block of code to timeout after a certain number of seconds.. I have been searching on this but haven't found anything yet on how to do this,
I was thinking something like this could work but I don't think it would dynamically update the $time variable, but maybe there is a way to get this to work? Any advice is appreciated
$time = time();
$timeout = $time + 5; //just as an example
do {
// do stuff
} while ($time < $timeout)
Your best bet would be to use proc_open, sleep for your timeout amount and then call proc_terminate if the process still hasn't completed.
See http://us3.php.net/manual/en/book.exec.php for details on the proc_* family.
Well, I'm not so sure this question would have an answer based on how I asked it, so what I am going to do is do the perl call where php doesn't wait for a response and have perl write the output to a text file, then have php read this after specified number of seconds, I think this is the simplest way to do this, its just for a small app i am running on a local server