🔭 Want to get alerted when your PHP scheduled tasks stop working?
Head over to Better Uptime start monitoring your jobs in 2 minutes
Task scheduling is a commonly used technique for automating tasks based on a schedule. Such tasks may include backing up databases, processing a queue, or creating system usage reports, as they are required to be repeated regularly over time, or even indefinitely. It is better to schedule such tasks and monitor them so they can run predictably in a timely fashion.
Many programming languages offer their own task scheduling solution, and in this tutorial, we will discuss how to create scheduled jobs using PHP. We will also discuss a monitoring solution to help you keep tabs on your scheduled tasks and promptly notify you if something goes wrong.
Head over to Better Uptime start monitoring your jobs in 2 minutes
Before going through the rest of this article, ensure that you are using a Linux
machine with the cron
installed. You also need the latest versions of
PHP and Composer installed.
In this tutorial, we will utilize the php-cron-scheduler package to implement task scheduling in PHP. It is a framework-agnostic package that can be integrated into any project or run as a standalone job scheduler.
You can go ahead and install this package in a new phpCronDemo
directory using
the commands below:
mkdir phpCronDemo && cd phpCronDemo
composer require peppeocchi/php-cron-scheduler
Using version ^4.0 for peppeocchi/php-cron-scheduler
./composer.json has been created
Running composer update peppeocchi/php-cron-scheduler
. . .
- Installing dragonmantank/cron-expression (v3.3.2): Extracting archive
- Installing peppeocchi/php-cron-scheduler (v4.0): Extracting archive
1 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
1 package you are using is looking for funding.
Use the `composer fund` command to find out more!
Once the package is successfully installed, a vendor
directory should be
present in the working directory. This directory should contain an
autoload.php
file that will be used to import the installed packages into our
program.
Create a scheduler.php
file at the root of your working directory and open it
in your text editor. It will serve as the starting point for all scheduled jobs
in this tutorial.
nano scheduler.php
Add the following code to the file:
<?php require_once __DIR__ . '/vendor/autoload.php';
use GO\Scheduler;
// Create a new scheduler
$scheduler = new Scheduler();
// Schedule jobs
// Run the scheduler
$scheduler->run();
First, you need to tell PHP where the autoload.php
file is located and then
import the Scheduler
class from the installed package. Next, create a new
instance of Scheduler
and run it using the run()
method. The scheduler
configuration is omitted for now, but it will be added in the next section.
Before this scheduler can start working, you must activate it by setting up a
Cron Job that executes the scheduler.php
script every minute. Open your
crontab
with the following command:
crontab -e
Add the following line to the end of the file:
* * * * * php <absolute_path>/scheduler.php
This Cron Job activates the scheduler by executing the script every minute so that the scheduler can evaluate your scheduled tasks and run the ones that are due. In the next section, you will define your first scheduled task and see it in action.
After you've created and activated your scheduler, you can start scheduling
jobs. The php-cron-scheduler
package offers three methods for this purpose,
depending on what type of job you wish to schedule. For example, the raw()
method is used to schedule the execution of a Linux command like this:
. . .
$scheduler = new Scheduler();
$scheduler->raw(
"curl https://en.wikipedia.org/wiki/Main_Page -o wikipedia.html"
);
$scheduler->run();
This particular example will schedule a curl
command which downloads the
Wikipedia homepage to an HTML file in the current directory.
At this point, you've defined the task to be scheduled. Next you need to define how often it should be executed. Let's make the job run every minute for example:
. . .
$scheduler = new Scheduler();
$scheduler
->raw("curl https://en.wikipedia.org/wiki/Main_Page -o wikipedia.html")
->everyMinute();
$scheduler->run();
Using the everyMinute()
method ensures that the scheduled task is executed
every minute. Once you save the scheduler.php
file, wait for a minute, and you
should observe the creation of the wikipedia.html
file. View the contents of
the file with the following command to confirm that it is working as expected:
cat wikipedia.html
<!DOCTYPE html>
<html class="client-nojs" lang="en" dir="ltr">
<head>
<meta charset="UTF-8"/>
<title>Wikipedia, the free encyclopedia</title>
. . .
</html>
You can also schedule PHP functions or scripts using the php-cron-scheduler
package as shown below. Note that functions always run in the foreground, while
scripts run in the background by default.
Here's how to schedule a PHP function using the call()
method:
$scheduler->call(
function ($args) {
return $args["user"];
},
[["user" => $user]],
"myCustomIdentifier"
);
The call()
method takes three parameters:
On the other hand, the php()
method is used to schedule PHP scripts as shown
below:
$scheduler->php(
"script.php", // The script to execute
"php", // The path to the PHP binary that is used to execute the script
[
"username" => "jack",
"verified" => true,
],
"myCustomIdentifier"
);
It takes four arguments, as shown in the list below, but only the first one is required:
Scheduling a script in this manner allows you to automate more complex tasks. For example, here is a script that retrieves the current weather information and saves it to a text file:
<?php
$location = json_decode(file_get_contents("http://ipinfo.io/json"));
$coordinate = $location->loc;
$coordinate = explode(",", $coordinate);
$weather = json_decode(
file_get_contents(
"https://api.openweathermap.org/data/2.5/weather?lat={$coordinate[0]}&lon={$coordinate[1]}&appid=<api_key>"
)
);
$text = "Todays weather is " . $weather->weather[0]->main;
$file = fopen("weather.txt", "w");
fwrite($file, $text);
fclose($file);
This script uses the ipinfo.io API to retrieve your
coordinates based on your IP address, then the coordinates are used to get the
current weather forecast through the
OpenWeatherMap API. Note that you need to register
for a free OpenWeatherMap account and replace the <api_key>
placeholder with
your API key.
Once the weather information is extracted, it is saved to a weather.txt
file.
You can schedule this script to run every morning at 06:00 AM like this:
<?php require_once __DIR__ . "/vendor/autoload.php";
use GO\Scheduler;
$scheduler->php("weather.php")->daily("06:00");
$scheduler->run();
Let's now discuss how you can set up an execution schedule for your tasks. The
php-cron-scheduler
package offers several other helpers besides the
everyMinute()
and daily()
methods we already covered. These helpers are
shown in the list below:
everyMinute()
: This helper defaults to every minute, but you can pass a
$minute
parameter to make the task run at a different interval. For example,
everyMinute(5)
will execute the job every five minutes.hourly()
: Schedules the job to run once every hour at minute 0. You can pass
a $minute
parameter so that the job runs at minute $minute
of the hour.
For example, hourly(15)
means the job will run at 00:15, 01:15, 02:15, and
so on.daily()
: Runs once every day. You can pass two parameters ($hour
and
$minute
) or a string (hour:minute
) to determine the exact time this job is
scheduled. If not set, the job will run at 00:00 every day.There are also additional helpers for weekdays. Just like daily()
, you can
pass parameters $hour
and $minute
or a string to set the exact time, but it
defaults to 00:00.
$scheduler->php("script.php")->sunday();
$scheduler->php("script.php")->monday();
$scheduler->php("script.php")->tuesday();
$scheduler->php("script.php")->wednesday();
$scheduler->php("script.php")->thursday();
$scheduler->php("script.php")->friday();
$scheduler->php("script.php")->saturday();
$scheduler->php("script.php")->saturday(10); # Saturday at 10:00
$scheduler->php("script.php")->saturday(11, 30); # Saturday at 11:30
$scheduler->php("script.php")->saturday("15:25"); # Saturday at 15:25
There are helpers for months as well, and they default to running on the first
day of the month at 00:00. You can pass three parameters $day
, $hour
and
$minute
to set the exact date and time if you wish. Note that these helper
methods do not accept a string as input.
$scheduler->php("script.php")->january();
$scheduler->php("script.php")->february();
$scheduler->php("script.php")->march();
$scheduler->php("script.php")->april();
$scheduler->php("script.php")->may();
$scheduler->php("script.php")->june();
$scheduler->php("script.php")->july();
$scheduler->php("script.php")->august();
$scheduler->php("script.php")->september();
$scheduler->php("script.php")->october();
$scheduler->php("script.php")->november();
$scheduler->php("script.php")->december();
$scheduler->php("script.php")->december(25); # December 25th
$scheduler->php("script.php")->december(25, 12, 30); # December 25th at 12:30
It is also possible for you to combine these helpers to create a more random schedule. For instance, if you want a job to run every Wednesday and Friday at 05:00 and 14:00, this is what you can do:
$scheduler
->php("script.php")
->wednesday("05:00")
->wednesday("14:00")
->friday("05:00")
->friday("14:00");
If you are more comfortable using Cron expressions,
you can use the at()
method to create the same schedule as follows:
$scheduler->php("script.php")->at("0 5,14 * * 3,5");
Lastly, a date()
method is provided for scheduling a task to be executed
exactly once on the specified date and time. The method takes a string or an
instance of DateTime
:
$scheduler->php("script.php")->date("2022-09-13 12:20");
$scheduler->php("script.php")->date(new DateTime("2022-09-13"));
One of the benefits of using PHP to schedule tasks instead of Cron is that you can harness the power of a programming language to define conditions other than a date and time for carrying out task execution.
The scheduler's when()
method is provided for this purpose. It takes a
callback function as its input, and the job only executes when the function
returns true
. For example, you can schedule a job that executes when PHP is
using more than 1MB of memory:
$scheduler->php("script.php")->when(function () {
if (memory_get_usage() >= 1048576) {
return true;
} else {
return false;
}
});
The php-cron-scheduler
package also provides some hooks for specifying any
functions to run before and after a scheduled job is executed. These are the
before()
and then()
methods shown below:
$scheduler
->php("weather.php")
->before(function () {
// execute this before evaluating `weather.php`
})
->then(function ($output) {
// execute this after evaluating `weather.php`
})
->everyMinute();
Notice the sequence of this chain of methods. The before()
and then()
methods come after the php()
method, followed by the scheduling method. The
$output
parameter in the then()
method is automatically injected by the
scheduler, containing the output of the weather.php
script (if any).
In the weather report example, the fopen()
function was used to write the
weather information to a local file. However, there is an easier and more
convenient way to deal with the output from scripts, commands, or functions
through the php-cron-scheduler
package.
First, you must ensure that your function, command, or script produces an
output. For example, you can modify your weather.php
file as follows:
. . .
$text = "Todays weather is " . $weather->weather[0]->main;
echo $text;
Next, go to your scheduler.php
file, and add an output()
method:
. . .
$scheduler
->php("weather.php")
->everyMinute()
->output(["weather.txt"]);
$scheduler->run();
For demonstration purposes, the schedule is changed to everyMinute()
. Wait for
the job to execute, then run the following command to see the output:
cat weather.txt
Todays weather is Clouds
The output()
method takes an array as its input, allowing you to save the
output to multiple files like this:
$scheduler
->php("weather.php")
->everyMinute()
->output(["weather.txt", "weather.log"]);
Better Uptime is a cloud-based monitoring tool that allows you to keep tabs on your scheduled jobs and get notified through if a task didn't execute as scheduled for any reason. This section will discuss how to configure Better Uptime to monitor your scheduled tasks.
First, you need to create a free Better Uptime account if you don't have one already. Once signed in, click Heartbeats on the top left of the dashboard and create a new heartbeat.
Choose an appropriate name for your monitor and select how often you expect this job to be repeated. In the On-call escalation section, pick how you wish to be notified when the job fails to execute. After you are done, click Save Changes.
You should see this page:
Notice the highlighted section in the middle. This URL is how Better Uptime monitors your scheduled task. Every time a job executes, you should ensure that a HEAD, GET, or POST request is made to this URL.
For example, head back to the scheduler.php
file and add the following
highlighted code:
. . .
// Schedule jobs
$scheduler
->php("weather.php")
->then(function () {
file_get_contents("https://betteruptime.com/api/v1/heartbeat/<api_key>");
})
->everyMinute()
->output(["weather.txt"]);
// Run the scheduler
$scheduler->run();
Here, the file_get_contents()
function is used to make a GET request to the
Better Uptime API each time the weather.php
script is executed. Next, go to
the Better Uptime monitor you just created and wait for the job to execute. Once
Better Uptime starts receiving requests, the monitor will be marked as "Up",
which means that the Cron Job is up and running.
You can simulate an incident by commenting out the file_get_contents()
line.
If Better Uptime does not receive a request within the configured time frame,
the heartbeat will be marked as "Down", which means that an incident was
detected.
You will also receive an alert in the configured channels:
In this tutorial, we discussed how to schedule tasks such as Linux commands, PHP functions and scripts using the PHP Cron Scheduler package. We also demonstrated how to specify conditional triggers for your tasks, and how to monitor scheduled task with Better Uptime.
There are many more options when it comes to using scheduling tasks in PHP in production, from sending emails to database backups. Hopefully, this guide gives you the basics to explore more on your own. If you are using Laravel, feel free to get more specific insight in our Laravel task scheduling guide.
Thanks for reading, and happy scheduling!
Are you a developer and love writing and sharing your knowledge with the world? Join our guest writing program and get paid for writing amazing technical guides. We'll get them to the right readers that will appreciate them.
Write for usWrite a script, app or project on top of Better Stack and share it with the world. Make a public repository and share it with us at our email.
community@betterstack.comor submit a pull request and help us build better products for everyone.
See the full list of amazing projects on github