Cron Jobs

By the end of this lesson you'll be able to read and write cron expressions, schedule a PHP CLI script to run automatically, log its output, and stop two runs from colliding — the toolkit behind every nightly backup and email digest.

Part of the free Php course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

What You'll Learn in This Lesson

1️⃣ Cron Syntax: The Five Fields

A cron job is a command your server runs automatically on a schedule. That schedule is written as five space-separated fields followed by the command: minute hour day-of-month month day-of-week command . An asterisk ( * ) means "every value", */5 means "every 5th", a dash like 1-5 is a range , and a comma like 1,15 is a list . Learn to read these six lines and you can express almost any schedule.

Cron itself prints nothing — it just launches the command at the right moment. The fields only decide when . A common gotcha: the day-of-month and day-of-week fields are OR-ed together, so 0 0 13 * 5 runs on the 13th and on every Friday, not only Friday the 13th.

2️⃣ Installing a Job with crontab -e

Each user has their own crontab (cron table). You edit it with crontab -e , which opens an editor; the moment you save, the schedule is live. The command in a cron line is run by a bare shell, so you give the full path to PHP and the full path to your script : /usr/bin/php /var/www/app/backup.php . Cron throws away your script's output unless you capture it — so always redirect it to a log file with > > file.log 2 > &1 (append stdout, and send errors to the same place).

3️⃣ The PHP CLI Script Cron Runs

The script cron launches is ordinary PHP, but run from the command line rather than a browser. That mode is called the CLI SAPI (Server API), and php_sapi_name() returns "cli" there. There is no web page, so everything you echo goes to stdout — which the cron line redirects into your log file. Finish with a clear exit code : exit(0) for success, anything else for failure.

Because each line is timestamped with date('Y-m-d H:i:s') , the log tells you not just that the job ran but when — the first thing you'll want when something breaks at 2 AM.

4️⃣ Preventing Overlap with flock

What happens if a job scheduled */5 * * * * sometimes takes seven minutes? Cron starts the next copy on top of the first, and now two runs fight over the same data. A file lock stops this: the first run grabs an exclusive lock; any later run that can't grab it simply exits. You can do this in the cron line with the flock command (shown in section 2) or inside PHP with the flock() function below.

5️⃣ Your Turn: Write a Cron Line

Now you write the schedule. The line below is almost complete — fill in each ___ using the field order and the 👉 hints, then check it against the Output panel.

One more — this time the PHP script. Cron will redirect its output to a log, so give every line a timestamp . Fill in the blanks and run it.

Common Errors (and the fix)

Pro Tips

6️⃣ Alternatives: systemd Timers & the Laravel Scheduler

Plain crontab is everywhere, but two alternatives solve its weak spots. systemd timers pair a .timer unit (when) with a .service unit (what), giving you centralised logging via journalctl -u myjob , dependencies, and easy enable / disable . The Laravel scheduler flips the model: you define all schedules in PHP and add a single cron line that runs php artisan schedule:run every minute.

📋 Quick Reference — Cron Fields & Commands

Field / Token

Range / Example

Meaning

1st field

minute (0-59)

Minute of the hour

2nd field

hour (0-23)

Hour, 24-hour clock

3rd field

day of month (1-31)

Day number in the month

4th field

month (1-12)

Month of the year

5th field

day of week (0-6)

0 = Sunday … 6 = Saturday

*

* * * * *

Every value (here: every minute)

*/n a-b a,b

*/5 1-5 1,15

Every nth · range · list

crontab -e / -l

crontab -e

Edit / list your cron jobs

> > log 2 > &1

> > job.log 2 > &1

Append output + errors to a log

flock

flock -n /tmp/j.lock cmd

Prevent overlapping runs

Frequently Asked Questions

Mini-Challenge: A Self-Protecting Heartbeat

No code is filled in this time — just a brief and an outline. Write it yourself, run it on onecompiler.com/php or your own machine, then check your result against the expected output in the comments. This combines the lock and the timestamped log into one real cron-ready script.

🎉 Lesson Complete!

Practice quiz

What is the correct order of the five cron fields?

  • hour, minute, day, month, year
  • day-of-week, month, day, hour, minute
  • minute, hour, day-of-month, month, day-of-week
  • second, minute, hour, day, month

Answer: minute, hour, day-of-month, month, day-of-week. Read left to right: minute (0-59), hour (0-23), day-of-month (1-31), month (1-12), day-of-week (0-6), then the command.

What does the cron expression '0 9 * * 1-5' mean?

  • 09:00, Monday to Friday
  • Every 9 minutes on weekends
  • 9 PM on the 1st to 5th of the month
  • Midnight every 9 days

Answer: 09:00, Monday to Friday. Minute 0, hour 9, any day-of-month, any month, day-of-week 1-5 (Mon-Fri) — so 9 AM on weekdays.

What does the token '*/5' mean in the minute field?

  • Exactly minute 5
  • Minutes 1 through 5
  • Five times total
  • Every 5th minute

Answer: Every 5th minute. * means 'every', */5 means 'every 5th', a-b is a range, and a,b is a list.

Why must you use absolute paths in a crontab command?

  • Cron only accepts uppercase paths
  • Cron runs with a bare environment, so 'php' or './script.php' may not resolve
  • Relative paths are a syntax error
  • Absolute paths run faster

Answer: Cron runs with a bare environment, so 'php' or './script.php' may not resolve. Cron uses a minimal PATH and a different working directory, so use /usr/bin/php /var/www/app/script.php — full paths to both.

How do you capture both normal output and errors from a cron job to a log file?

  • >> file.log 2>&1
  • | file.log
  • > file.log only
  • 2>file.log only

Answer: >> file.log 2>&1. >> appends stdout to the log and 2>&1 sends stderr to the same place. Without this, a failing job is silent and undebuggable.

Which command opens your personal crontab in an editor?

  • crontab -l
  • crontab -r
  • crontab -e
  • cron --edit

Answer: crontab -e. crontab -e edits (and installs on save), crontab -l lists, and crontab -r removes ALL of the user's jobs.

How do you stop two copies of a cron job from running at the same time?

  • Schedule it less often and hope
  • Wrap it in flock with a lock file (or call flock() in PHP)
  • Run it as root
  • Add MAILTO to the crontab

Answer: Wrap it in flock with a lock file (or call flock() in PHP). flock -n /tmp/job.lock (or PHP's flock($handle, LOCK_EX | LOCK_NB)) makes a second run exit instead of overlapping.

In a PHP CLI script, what does php_sapi_name() return when run from cron?

  • 'fpm'
  • 'cron'
  • 'apache'
  • 'cli'

Answer: 'cli'. From the command line (and cron) PHP runs as the CLI SAPI, so php_sapi_name() returns 'cli'.

Which exit code signals a successful cron run?

  • exit(1)
  • exit(0)
  • exit(200)
  • exit(-1)

Answer: exit(0). exit(0) means success; any non-zero code is recorded by cron as a failed run.

Which is a modern alternative to plain crontab on a single server?

  • An infinite PHP while-loop
  • A browser refresh tag
  • systemd timers (a .timer plus a .service unit)
  • A Composer script

Answer: systemd timers (a .timer plus a .service unit). systemd timers give logging via journalctl, dependencies, and easy enable/disable; the Laravel scheduler keeps timing logic in PHP with one cron line.

Continue this course