I think Cron may be the best answer for this, but the task seems daunting and I know so little about cron, it's probably best that I ask first.
I am writing an API for an iPhone application that schedules shared tasks in a group. This will require sending push notifications at various times. Here is one example:
Person A assigns a task for Person B to complete in n days. This task is added, Person B is notified that the task has been assigned and after n-1 days a reminder notification is sent, if the task was not completed after n days, another notification is sent alerting Person B that they failed to complete the task.
My assumption here is that the process would go something like this:
When the task is initially assigned and the task is added to the DB, a cron scheduling script would be called which would schedule 2 cron jobs - 1 to fire the reminder notification, and one to fire the failure notification.
When the task is completed, it calls another script which either marks the task as completed in the DB (or removes it), and un-schedules the cron jobs.
Am I way off base here, or is this the easiest way to take this on? If it is - are there any PHP classes to make dynamically scheduling (and un-scheduling) cron jobs easier?
You could have a cron job that fires once every day.
This loops through data in the database, if a reminder needs to be sent (e.g. n-1 days is today, send the notification).
If that date has passed and it isn't complete, then it can send the failure notification.
If the task is complete, then you can change the database in that cron task, or a seperate one that fires more often.
Hopefully that helps.
My advise would be: determine what the fastest response needed would be (every minute, every 10 minutes, every hour etc.) and run a cron script in that time frame.
The script itself could be PHP, en when the script runs it figures out what to do, what actions are needed etc.
I worked on a mailing queue recently, and I implemented it as follows:
There is a one cron job that fires every minute a script, that check if database contains any e-mails in the queue. If they are found, script sends them out.
There is another cron job, that fire every day which adds scheduled e-mails to database (with a specified time, when to send it out).
So, there is a daily cron job that generates jobs to be processed at various times, and there is another one which runs constantly and processes jobs in queue.
It's easy to add some priority mechanisms too.
Your host will likely offer a cron capability in your hosting control panel. The few times I have used it, I have found that it is a case of putting in the file that you want to run's path on the server then from a couple of drop downs select the frequency. From there you are off..
As for the solution you could have AS A VERY SIMPLE EXAMPLE...
cron.php
<?php
/*
Steps
1 - Set any completed tasks to done
2 - Check if users need to be notified and send the notifications
*/
function send_notifications($email,$time_ends){
// insert code here to deal with sending the notification to the iphone
}
include("db.php"); // contains your MySQL connection vars or whatnot
// STEP 1 - Set any completed tasks to done
$update_db = mysql_query("UPDATE Notifications SET complete = '1' WHERE time_completed > '0000-00-00 00:00:00'");
// STEP 2 - Send any outstanding notifications out
$result = mysql_query("SELECT * FROM Notifications WHERE time_completed = '0000-00-00 00:00:00'"); // add another where clause to prevent bombarding with notifications for example " AND notification_2_days = '0'"
while($row = mysql_fetch_array($result))
{
send_notifications($row['email'],$row['time_ends']);
// insert an update query here to flag as a notification sent, you dont want to bombard
}
?>
WARNING - This is using depreciated connection code for simplicity (look up MySQL PDO etc) and this lacks any kind of security.
cron is great for scripts run on a regular basis, but if you want a one-off (or two-off) script to run at a particular time you would use the unix 'at' command, and you can do it directly from php using code like this:
/****
* Schedule a command using the AT command
*
* To do this you need to ensure that the www-data user is allowed to
* use the 'at' command - check this in /etc/at.deny
*
*
* EXAMPLE USAGE ::
*
* scriptat( '/usr/bin/command-to-execute', 'time-to-run');
* The time-to-run shoud be in this format: strftime("%Y%m%d%H%M", $unixtime)
*
**/
function scriptat( $cmd = null, $time = null ) {
// Both parameters are required
if (!$cmd) {
error_log("******* ScriptAt: cmd not specified");
return false;
}
if (!$time) {
error_log("******* ScriptAt: time not specified");
return false;
}
// We need to locate php (executable)
if (!file_exists("/usr/bin/php")) {
error_log("~ ScriptAt: Could not locate /usr/bin/php");
return false;
}
$fullcmd = "/usr/bin/php -f $cmd";
$r = popen("/usr/bin/at $time", "w");
if (!$r) {
error_log("~ ScriptAt: unable to open pipe for AT command");
return false;
}
fwrite($r, $fullcmd);
pclose($r);
error_log("~ ScriptAt: cmd=${cmd} time=${time}");
return true;
}
Related
Trying to make a dice-roll function in my telegram bot.
How it works right now:
When a user sends "roll" bot replies with sendDice method and sends another message with result like "you rolled 5, you won and blah-blah .."
> how it looks <
The problem is — the second message should not appear instantly, ideally after dice-roll animation is finished.
My first and obvious try on that was to add "sleep(3)" before sending the second message, and it worked fine, until I realized it completely delays the execution of my script for those 3 seconds. (if two users rolled at the same time, one of the users has to wait until another guy's roll will be finished). So it's not cool
What can I use? :c
The easiest option is to add the "task" to the "queue". The queue can be a table in the database with timestamps and chat id, when and to whom to send a message. Start another process, for example, which is started by cron, and it works for one minute. During that minute, he goes to the database and checks to see if there is something that needs to be sent now.
Crontab config
Open crontab
sudo crontab -e
Add next string
* * * * * php /path/to/cron.php >> /path/to/log/file/for/debug.log 2>&1
Cron run your script every 1 minute.
Cron.php "live" 60 second
cron.php:
$now = time();
$expectedTime = $now + 60;
while (true) {
Worker::run();
if ($expectedTime < time()) {
die(0);
}
}
Where Worker::run() your method, which get records from db, check timestamp and send message
From Wikipedia:
In computing, [..] fork is an operation whereby a process creates a
copy of itself.
When your PHP script runs, you can create multiple processes that interact with each other. Those processes run concurrently and asynchronous. This way you can have one process waiting to send the message, while the rest of the script continues to run.
Instead of starting another process, you could also start another thread. The technical difference between the two is explained here:
Forking vs Threading
PHP offers Process Control Extensions for both forking and threading. You might want to check out the example in the PHP documentation for pcntl_fork().
Depending on your needs, you might want to use a framework designed to handle concurrency throughout your application. If that is the case, I would recommend amphp.
put in simple words:
i am writing php scripts which send and receive sms,
scripts will calculate to send users campaign SMS every week based on each user registration date, for example every monday 10 AM send sms to mr. A and every friday at 7 pm sends sms to miss B..
and php scripts will take care of everything needed ..
problem : obviously a very funny way is to have someone refresh the main page of my application every some seconds or so to be able to continue to calculate and understand what and when to do jobs, or have the main page always open on my computer so javascripts and jquery will handle the rest!
My Question : how can i have my php program or scripts to be something like awake without need to someone refreshes or have open the main page? by awake i mean like it senses the next schadule and executes it and so on ..
some raw ideas to answer : perhaps i could call the main page using ajax or curl every 10 seconds .. but i don't know how to awake ajax or curl in first place ..
i see some internet posts suggest something like command line either in linux unix or windows .. but i usually access the host not the command line is it right ? or command line is something in host and i don't know it, if so please help me ..
important example : there are php wp plugins like total cache and supper cache which seem to be always on and awake of schedules without need of somebody refreshing a page ..
please give answers all in php and php families if possible, i don't know unix or those kind of programmings at all ..
------- accourding to answers made some progress to question ..
now i have this bellow script :
ignore_user_abort(true);
set_time_limit(0);
$data = file_get_contents('filename.txt');
$data = $data+1;
file_put_contents('filename.txt', $data);
$page = $_SERVER['PHP_SELF'];
$sec = "4";
header("Refresh: $sec; url=$page");
it works! even when i restart the local host . main problem is now when i closed the main page it stopped incrementing in filename.txt and when reoppend the page two instance where running the increment continued so :
should'nt it continue to increment even when i close the page ?
and how i stop it ?
and is it normal to have more than one instance of the page run in background?
finally : according to instructions on this page it's best i create a starter or reload page then use commands to initiate this reload page for example every 1 minute and then write PHPs like normal ..
last not least : how to stop this background script ? for update or maintenance ..
For this particular issue cron jobs have been invented. Cron jobs are timed jobs that can for example execute a PHP script.
You could set up a cron job to check which user should receive his/her sms every hour. Depending on your operating system you can set up these cron jobs. For linux distrubutions there are tons of guides on how to set this up.
From Wikipedia:
The software utility Cron is a time-based job scheduler in Unix-like computer operating systems. People who set up and maintain software environments use cron to schedule jobs (commands or shell scripts) to run periodically at fixed times, dates, or intervals. It typically automates system maintenance or administration—though its general-purpose nature makes it useful for things like downloading files from the Internet and downloading email at regular intervals. The origin of the name cron is from the Greek word for time, χρόνος (chronos). (Ken Thompson, author of cron, has confirmed this in a private communication with Brian Kernighan.)
I have added a resource explaining how to use cron jobs.
An alternative method is to keep a PHP script running in the background:
// Keep executing even if you close your browser
ignore_user_abort(true);
// Execute for an unlimited timespan
set_time_limit(0);
// Loop infinitely
// If you create a file called stop.txt,
// The script will stop executing
while (!file_exists('stop.txt')) {
// Retrieve user data and sens sms messages
// Wait for an hour
sleep(3600);
}
Update
ignore_user_abort(true);
set_time_limit(0);
$data = file_get_contents('filename.txt');
while (!file_exists('stop.txt')) {
// Add 1 to $data
$data = $data+1;
// Update file
file_put_contents('filename.txt', $data);
// Wait 4 seconds
sleep(4);
}
To stop executing create a file called stop.txt
Resources
About Cron jobs
You can create cron jobs in almost all servers without accessing command prompt.
Cron job can be used to initialize php scripts in cli at specified intervals lik every minute, every hour etc
I am new at php and using Yii framework.currently I am facing a problem how to send a mail to an user. I have a table which has a date field which indicates when the e mail needs to be sent. This date field is not the same for every user. When the date time comes the system will send a mail to the specific user. How can I do this. If anybody can give me some code example,that will be much more helpful. I do not want to use corn job. Need some code example.
Table:
User_id job_title_id cv_type review_date status
A B C 16/05/2015 yes
To be honest a cron job (linux) or task scheduler (windows) are specially useful for these kind of situations and I highly recommend you to use these builtin OS features but since you asked otherwise here I go:
A possible solution in php would be to create an infinite loop with a sleep in it like:
while(true){
try{
// Here should be the actual functionality to check the database
// and send e-mails to the specific user(s) if needed.
} catch(\Exception $e) { //this try catch exists to catch all exceptions that could crash this script.
echo $e->getMessage();
//notify yourself (by email) that an error has occurred
}
sleep(60*60); //In this case 1 hour sleep 60 seconds * 60 = 60 minutes
}
The downside is that you'll have to manually start the job once, that is if the world was prefect... But since the script could run into an PHP fatal error or server reboot you'll have to manually reboot this script each time. To start the script in linux do something as the following:
nohup php script_name.php >> error.log & // nohup prevents the script from being closed when you exit the terminal
Alright, So users in my game have an hourly income. Each hour I have a cronjob run to check and see if it's time for them to be payed. It works and all, But I want to stop using cronjobs as much. Here's the coding. The coding works and I've done things without a cronjob before by using a timestamp and calculate if it's ready for the user to be able to do the function, but they have to be logged in for that. If the users not logged in for a day or so would still like them to get their hourly income each hour without cronjob.
Here's the coding:
<?php
$result = mysql_query("SELECT * FROM users ORDER BY id");
while($row = mysql_fetch_array($result)) {
$total_pay = $row['income'] - $row['upkeep'];
$timestamp_hour = time() + 3600;
$inactive_time = strtotime('+1 week',$row['last_login']);
if(time() > $inactive_time) {
$income_add = '';
echo '<div style="color: red;">'.$row['username'].' | <i>Inactive</i></div>';
}
elseif(time() < $inactive_time) {
$income_add = mysql_query("UPDATE users SET cash=(cash+".$total_pay."),energy=(energy+".$e_income.") WHERE id=".$row['id']."");
$update_time = mysql_query("UPDATE users SET payment=".$timestamp_hour." WHERE id=".$row['id']."");
echo '<div style="color: green;">'.$row['username'].' | <i>Active</i></div>';
$res = $income_add & $update_time;
}
}
?>
Would their be a way to do so without a cronjob?
Since everyone in the comments are saying the same thing - I would like to put in the same input with as much details as possible as to why you should leave it as a cron job.
1) Without a cron job or job that runs infinite with a sleep (which in essence is a cron job by itself) there is no PHP being done UNLESS you drive enough traffic that your script gets activated by a user visit (ie check if last run was more than current time, then activate)
2) the sole purpose of a cron job is to activate a set script on the clock X amount of determined time...
3) if you write your cron job effecive enough with enough fail safe you can have it small on ressources such as:
a) dont overload memory with large arrays
b) dont pull large amount of data and let it lock your table.
c) make your cron job select specific amount of data and terminates with it...if there is left over the cron job will activate itself and continue to do work until it catches up. Once caught up it will terminate quick and easy.
4) you have mentioned that people are paid at different times - the cron job shouldnt restrict that - it is up to your code and models to effectively check those time vs time now checks in order to update, so that the cron can do work when it is needed or sleep when it is not suppose to , as an example i can make a cron wake up every 5 mins but inside the code it can check current time vs last run time (via a select or last written log) and check if it should run or not. So with that you shouldn't believe that having a cron run on the clock will prevent different circumstances of your code to activate.
You can run this without a cron job on your server by using a monitoring service. Follow these steps:
Place your php script somewhere in your web path.
Open a free site monitoring account at http://www.montastic.com/
Point the site checker to the script's URL: www.YourSite.com/yourscript.php
Set the monitoring interval to 1 hour.
Enjoy!
I am creating a service where users submit data that is stored in a MySQL database or text file and emailed to a specific address at a certain time each week.
I understand that this is not what PHP is for and I've read of something called Cron that does the job, but I was wondering if there are any other options? Is there a script that could send from Gmail perhaps with the data pasted or attached?
I can only think in two ways to do it:
Having a cron job to call your send script every x minutes
$database->query("SELECT * FROM `mail_queue` WHERE `time` < " . time());
while($object = $res->fetch_object()){
mail($object->to, $object->subject, $object->message, "FROM: xpto#domain.com");
}
(If you're using a webhosting account you can simply create it on the control panel)
* * * * * /bin/php complete_path_to_your_php_script.php
Having a script running in a loop (not reliable as it can stop working due to a timeout, error, memory outage, ...)
The best way is to use Cron jobs. If for some reasons you are not able to use them then you can use services of thecloudblocks.com which allows you to schedulejobs.
Alternatively, you can create a function to sleep untill the time for the job comes. Like,
function do_some_job_at($time){
time_sleep_until($time);
JOB();
}
do_some_job_at(time() + 20); //Runs job after 20 seconds.
If you need the php script to be running at all times then I would suggest using upstart jobs / services