How to Execute a Script at Specific Time, Only Once, using PHP

Can Cron be used to Execute a Script Only Once ?

Unfortunately not. The purpose of cron is to execute a job repeatedly at regular intervals of time. Of course it is possible to add a cron job and then delete it after the job has been executed once, but it is not a very good method.

To run a PHP script at a given time only once, use the Linux's at command. at schedules a job to be executed only once.

Installing at

In Ubuntu 14, at is present by default.
In Ubuntu 16 you can install at through the command line.

sudo apt install at

Modifying at.deny Configuration File

at.deny configuration file present in /etc directory contains the list of programs which are not allowed to run the at commmand. In both Ubuntu 14 & 16, the Apache program (which is named www-data) is not allowed to run the at command by default. So you need to edit this file and remove the www-data entry.

sudo nano /etc/at.deny

Using at in Command Line

The at command is of the form :

at -f file-to-execute hh:mm YYYY-MM-DD

file-to-execute is a file that contains the commands that will be executed at the time hh:mm YYYY-MM-DD. An example can be :

at -f /var/www/html/tests/command.txt 23:47 2016-12-13

The above command schedules the file "/var/www/html/tests/command.txt" to be executed at "23:47 2016-12-13". This file can contain a command like wget or curl that will call a specified url. An example of the file contents can be:

wget -O /dev/null "http://localhost/tests/cron-execute.php?id=123&tr=456"

The output of running an at command will be like :

warning: commands will be executed using /bin/sh job 25 at Tue Dec 13 23:47:00 2016

So a job number is assigned to each job that is to be executed. This job number is important, because if we want to delete this job we will need this job number.

atrm 25

atrm command deletes a specified job identified by its job number.

If you want to see the list of jobs to be executed, use atq command.
In case you need to see the list of jobs that are added through PHP use sudo atq(Apache is the owner of the jobs that are created through PHP so we need sudo privileges).

Using at in a PHP Script

at command can be executed through a PHP script using exec function. The output of this function can be parsed with a regular expression to get the job number (or to find whether at failed). The application can keep the job number in a database so that it can delete the job later if required.

<?php // Create the file that is required in at command // This file has the wget command that will call a url at the time when the job is scheduled file_put_contents('at-file.txt', 'wget --no-check-certificate -O /dev/null "http://localhost/ticket/ajax.php?operation=ProcessOrder&order_id=12"'); // Run at command // Give the full path of the file exec('at -f /var/www/html/ticket/at-file.txt 23:47 2016-12-13 2>&1', $output, $return_value); // Get the job number from the output preg_match('/(?<=job )\S+/i', implode("\n", $output), $match); if(sizeof($match) == 0) { echo 'Error : Job Scheduler Failed'; } else { $job_id = $match[0]; } ?>

It is advisable to save the activty log of wget command to a file. If an error occurred at the scheduled time, at least you will know what happened.

wget -O /dev/null "http://localhost/tests/cron-execute.php?id=123&tr=456" 2>> /var/www/html/tests/log.txt