PHP CLI Scripts, Cron Jobs, and Automation
PHP is useful beyond web requests. CLI scripts can import data, process queues, run maintenance, synchronize APIs, and perform repeatable operational tasks.
A Safe CLI Entry Point
#!/usr/bin/env php
<?php
declare(strict_types=1);
require dirname(__DIR__) . '/vendor/autoload.php';
if (PHP_SAPI !== 'cli') {
fwrite(STDERR, "This command must run from the CLI.\n");
exit(1);
}
$options = getopt('', ['file:', 'dry-run']);
$filename = $options['file'] ?? null;
$dryRun = array_key_exists('dry-run', $options);
if (!is_string($filename) || !is_readable($filename)) {
fwrite(STDERR, "Usage: import.php --file=/path/data.csv [--dry-run]\n");
exit(2);
}
fwrite(STDOUT, $dryRun ? "Dry-run mode enabled.\n" : "Import starting.\n");
Exit Codes Matter
| Code | Meaning |
|---|---|
0 | Successful completion |
1 | General runtime failure |
2 | Usage or validation error |
Schedulers and monitoring systems use exit codes to determine whether a job succeeded.
Prevent Overlapping Runs
<?php
declare(strict_types=1);
$lock = fopen(sys_get_temp_dir() . '/customer-sync.lock', 'c');
if ($lock === false || !flock($lock, LOCK_EX | LOCK_NB)) {
fwrite(STDERR, "Another sync is already running.\n");
exit(1);
}
try {
// Run the synchronization.
} finally {
flock($lock, LOCK_UN);
fclose($lock);
}
Design for Retries
- Make operations idempotent whenever possible.
- Checkpoint progress for large imports.
- Use unique external IDs to prevent duplicates.
- Set timeouts on network calls.
- Retry transient failures with backoff and a limit.
- Send permanent failures to a review queue.
Cron Example
*/5 * * * * /usr/bin/php /var/www/app/bin/process-queue.php \ >> /var/log/app/process-queue.log 2>&1
Use absolute paths and a predictable environment. Cron often has a smaller PATH and different environment variables than an interactive shell.
Long-Running Workers
Release database transactions promptly, reconnect after failures, cap memory growth, and restart workers after a reasonable number of jobs. Deployments should signal or replace old workers so they do not continue running outdated code.