Preventing Multiple PHP Script Executions in CRON — A Smart and Reliable Approach
Running a PHP script every five minutes with CRON is simple enough.
But delays in processing can leave the previous instance still running, causing unexpected multiple executions that lead to log pollution or database conflicts. Sound familiar?
This article explains a reliable solution to this common issue, combining a straightforward “basic setup” with essential safety measures to ensure stable operation.
Setting Up CRON to Run a PHP File Every 5 Minutes
For example, suppose you configure the following settings using crontab -e.
- Execute every 5 minutes
- Save both standard output and error output to a log file
-
Specify the PHP command using an absolute path.
If you don’t know the absolute path, use thewhich phpcommand to check it.
The-foption can be included or omitted — both work the same. - The PHP script to execute is assumed to be specified with an absolute path.
Without the -f option:
*/5 * * * * /usr/bin/php /home/mam/cron/task.php >> /home/mam/log/task.log 2>&1
With the -f option:
*/5 * * * * /usr/bin/php -f /home/mam/cron/task.php >> /home/mam/log/task.log 2>&1
After configuring, check it with crontab -l.
PHP Source Code
This script stops execution if another process is already running with the same full‑path PHP filename.
<?php
// Check whether this PHP file (invoked by CRON) is already running as a process.
// Processes are launched as either "php -f filename" or "php filename".
$processes = [];
exec('pgrep -f '.'"php.+'.preg_quote(__FILE__).'"', $processes);
if(count($processes)>1){
echo "[".date('Y-m-d H:i:s')."] Another process with the same filename is already running(".implode(",",$processes)."), aborting. (PID=".getmypid().")\n";
exit();
}
echo "[".date('Y-m-d H:i:s')."] Process started(PID=".getmypid().")\n";
//Wait for 10 seconds
for($i=0;$i<10;$i++){
//1秒待つ
sleep(1);
echo " ".($i+1)."seconds elapsed\n";
}
echo "[".date('Y-m-d H:i:s')."] seconds elapsed(PID=".getmypid().")\n";
- preg_quote(__FILE__)
- Escapes regex meta characters such as
.and+, converting__FILE__into a safe pattern string. - pgrep -f
- Searches for processes whose command line matches the regex pattern containing
"php.+filename". - count($processes) > 1
- Indicates that another process with the same filename exists, meaning a duplicate execution is occurring.
- sleep(1)
- Outputs progress every second as a placeholder task.
usleep(1000000)works the same.
Reference
Checking Processes for a Specific User
Add the -u switch.
pgrep -u <username> -f "regular‑expression‑pattern for the full command line"
When CRON Uses a Relative Path
In real environments, CRON entries are sometimes written using relative paths.
In such cases, the path in __FILE__ will not match the command line, so using basename(__FILE__) for comparison is effective.
Note: Since basename(__FILE__) matches only the filename, it may cause false positives if multiple files share the same name.
*/5 * * * * php ./task.php
exec('pgrep -f '.'"php.+'.preg_quote(basename(__FILE__)).'"', $processes);
