tags:

views:

1756

answers:

6

I have a file "update.php" which does some MySQL operations. A cron job executes this file every 5 minutes. Unfortunately, I cannot execute the cron job more often.

So I had the idea that I could add ...

<html>
<head>
  <meta http-equiv="refresh"  content="2; URL=<?php echo $_SERVER['SCRIPT_NAME']; ?>" />
</head>
<body></body>
</html>

... to the page "update.php". Will cron execute the file in a way that the page will refresh automatically? Or will that not happen because there is no client with a browser?

If it the meta refresh has no effect, is there any other possibility to achieve the refreshing of the page?

Thanks in advance!

A: 

What you are trying to do it implies user interaction, so what if no client enters into your "page"?

For example Servlets and EJB containers can do it programmatically at container startup what you need, so I suppose that for PHP the only way to accomplish "automatically" cronlike jobs is to make some changes in your Apache source code, obviously only if you are using an housing server.

A more praticable option not contempling code changes could be some cron script calling directly your page (wget,netcat,etc...) launched during your web server startup

Steel Plume
+9  A: 

I'm afraid that won't work, because it's a browser feature to refresh the page.

Question: Why can't you set the cron job to run more frequently that every 5 minutes?

If there is no other option then you could create you're own daemon to do the job more frequently.

e.g. Your php script could:

  • Run
  • Wait 60 seconds
  • Run
  • ( Wait; Run; two more times)
  • exit

For example: (By variation of sshow's code)

<?php

$secs = 60;

ignore_user_abort(true);
set_time_limit(0);

dostuff();
sleep($secs);
dostuff();
sleep($secs);
dostuff();
sleep($secs);
dostuff();
sleep($secs);
dostuff();

?>

This version of the script will remain resident for four minutes, and execute the code 4 times which would be equivalent to running every minute, if this script is run by cron every 5 minutes.

There seems some confusion about what a cronjob is, and how it is run.

cron is a daemon, which sits in the background, and run tasks through the shell at a schedule specified in crontabs.

Each user has a crontab, and there is a system crontab.

Each user's crontab can specify jobs which are run as that user.

For example:

# run five minutes after midnight, every day
5 0 * * *       $HOME/bin/daily.job >> $HOME/tmp/out 2>&1
# run at 2:15pm on the first of every month -- output mailed to paul
15 14 1 * *     $HOME/bin/monthly
# run at 10 pm on weekdays, annoy Joe
0 22 * * 1-5    mail -s "It's 10pm" joe%Joe,%%Where are your kids?%
23 0-23/2 * * * echo "run 23 minutes after midn, 2am, 4am ..., everyday"
5 4 * * sun     echo "run at 5 after 4 every sunday"

So to run every five minutes:

*/5 * * * *     echo "This will be run every five minutes"

Or to run every minute:

* * * * *       echo "This will be run every minute"

The output from the commands are emailed to the owner of the crontab (or as specified by MAILTO). This means if you run something every minute it will email you every minute, unless you ensure all normal output is suppressed or redirected.

The commands are run as the user who owns the crontab, which contrasts with the scripts run by the web-server, which are run as the 'nobody' user (or similar - whatever the web-server is configured to run as). This can make life more complicated if the cronjob is writing to files which are supposed to be accessed by the scripts run by the web-server. Basically you have to ensure that the permissions remain correct.

Now, I'm not sure that this is the system you are refering to. If you mean something else by cronjob then the above might not apply.

If you want to do something that your current host is not letting you do, then rather than hacking around the restriction, you might what to look at switching hosting provider?


An alternative is to put the script in you're normal scripts location, and have some external scheduler run wget against it at whatever frequency you like.


Another alternative is on-demand updating of the form of vartec's suggestion. However that may not solve your problems.

Douglas Leeder
Thank you! So I have to choose another way to achieve it. Your proposal seems to work. But there is a limit for simultaneously executed scripts on my server, I think. And there's the max. execution time. The script would then be executed non-stop (limit-1). Will it work, though?
There should only be one copy of this script running at any point (each copy should terminate after 5 minutes) (You might want to make it four minutes to be sure). And what's enforcing the max. execution time? If it's apache then that doesn't matter, as this is running outside apache.
Douglas Leeder
OK, thx. I thought that it's enforcing the max. execution time because: The script runs for 6secs, then it sleeps for 45secs. Using a loop, you repeat this five times. So you have a cronjob which runs one time per minute. The sleep time doesn't count but 6x6=36secs is the execution time (max 30).
Sorry, Douglas Leeder, but I don't know much about cronjobs so I didn't understand your edits. Could you explain them again, please? I use a cronjob service on the web but the minimal frequency is 5min. So I need sleep() to run that more often. What does NB2 mean? What differences does that make?
I think you might be meaning something slightly non-standard by cronjob. I'll try to clarify things.
Douglas Leeder
very nice answer, you've earned your bounty!
tharkun
Thanks. Perfect! "An alternative is to put the script in you're normal scripts location, and have some external scheduler run wget against it at whatever frequency you like." That's exactly what I meant. But my external scheduler can only run every 5 minutes. So I need your code which you posted above. Thanks!
"Your external scheduler" is where ever you put it, and runs as frequently as you want.
Douglas Leeder
+1  A: 

Update: Editted based on new information.

Meta refresh won't work because cronjob.de will be using an automated system that doesn't actually read the contents of the page. No browser, so nothing to see the meta refresh.

You have a couple options. They vary in greater or lesser horribleness.

The best option is to change webhosts. A good webhost will have full support for cron. But if you need to touch cron, honestly, you should probably be on a VPS host anyways. A lot of hosts will object to a cron task running every minute unless the task is just updating something really quickly and exits. But VPS hosts won't usually care. Slicehost offers VPS servers for as little as $20/month. Not recommended for people who've never had root access before.

The only option you've got that will work with cronjob.de's 5 minute limitation is to build a loop that will run an iteration, sleep, run another iteration, and repeat however many times you need before the end of the 5 minutes. However, there are two major problems with this approach. First, if you have a request that lasts 4 minutes, there's a distinct possibility that your webhost might kill the request before it finishes. Second, if the webserver isn't configured just right, such a request might block other requests, preventing legitimate users from accessing your site — they would queue up, and be waiting for the cronjob.de request to finish before their requests could be completed. And since that request will take 4-5 minutes to finish, before being repeated a minute later, they might only be able to access your site once every 5 minutes. I'm guessing this is undesirable. Unfortunately, the only way to know if you'll run afoul of either of these problems is to ask your webhost. I don't recommend trying it before asking, because they may not appreciate it if it goes unexpectedly bad and starts affecting their other customers on the server.

If you're lucky, they may even be willing to set up a cron job for you.

Bob Aman
Thanks for your answer! My webhost doesn't offer cronjobs at all. So I user cronjob.de, a German web service where you add URLs which are opened every 5 minutes. But 5 minutes is not enough. I need a smaller interval. So I search for a solution here.
Ahhh, yes, that explains things a bit more. In that case, PHP isn't a completely crazy idea. This probably should've been mentioned in the original question.
Bob Aman
+2  A: 

I'd say don't try to do this with php, change your crontab. If you need your application to do a cronjob every minute and your hosting doesn't provide this option, you have most likely outgrown your hosting. Get yourself a VPS hosting for 20$ a month (Slicehost, Servergrove).

tharkun
+2  A: 

I'm pretty sure you can achieve it by doing this:

<?php

$secs = 120;

ignore_user_abort(true);
set_time_limit(0);

while (true)
{
    // do something

    // Sleep for some time
    sleep($secs);
}

?>

Edit

You will have to execute it once after every server restart unless you do it like Douglas describes.

Update

Keep Douglas Leeder's answer in mind, and then take a look at this:

http://www.php.net/manual/en/function.ignore-user-abort.php

sshow
Thanks! I testet it - and it works. So I can create a script running (almost) for an unlimited period. But doesn't that "hurt" the server?Is the ignore_user_abort(true) really necessary? How can PHP realize that the user closed the page (the client disconnected)?
Doesn't matter if it realizes or not. It just doesn't end execution.
sshow
So you don't need ignore_user_abort(true), do you?
Take a look at the answer now.
sshow
Sorry, but I still don't understand. Your answer and Douglas Leeder's answer are almost the same concerning the script. Do you mean that ignore_user_abort(true) is missing in Douglas' code?
If you can make your server run update.php every 5 minutes, you won't need the ignore_user_abort().Then just make a while loop with a sleep() that'll end before the 5 minutes have passed. (or-else you would have 2 or more update.php running simultaneously)
sshow
A: 

You can use PHP to call the script...

<?php
$script='/path/to/my/php/script.php';

ignore_user_abort(1);
set_time_limit(0);
$php=exec('which php');
while (1) {
    if (file_exists($script)) { exec($php.' '.$script); }
    else { file_get_contents($script); }
    sleep(2);
}
?>

The file you give $script needs to exist, otherwise it thinks it's a URL.

It should do the trick.

HM2K
Thank your for that answer. But why do I need exec()? My script which should be invoked is also PHP. So I can use include() or just use one single file. Right?