option('run-only'); $installOnly = (bool) $this->option('install-only'); if ($runOnly && $installOnly) { $this->error('فقط یکی از --run-only یا --install-only را بزنید.'); return self::FAILURE; } if (! $runOnly && ! $this->installCronLine()) { return self::FAILURE; } if ($installOnly) { return self::SUCCESS; } $this->info('==> php artisan schedule:run'); return $this->call('schedule:run'); } private function installCronLine(): bool { $php = trim((string) ($this->option('php') ?: PHP_BINARY)); $artisan = base_path('artisan'); $marker = $artisan.' schedule:run'; $line = "* * * * * {$php} {$artisan} schedule:run >> /dev/null 2>&1"; $existing = $this->currentCrontab(); if ($this->crontabHasLine($existing, $marker)) { $this->info("cron از قبل نصب است: {$artisan}"); return true; } if ($this->option('dry-run')) { $this->line($line); return true; } $payload = trim($existing); if ($payload !== '') { $payload .= "\n"; } $payload .= $line."\n"; $tmp = tempnam(sys_get_temp_dir(), 'khaneghi-crontab-'); if ($tmp === false) { $this->error('ساخت فایل موقت crontab ناموفق بود.'); return false; } file_put_contents($tmp, $payload); exec('crontab '.escapeshellarg($tmp).' 2>&1', $output, $code); @unlink($tmp); if ($code !== 0) { $this->error('نصب crontab ناموفق بود.'); foreach ($output as $row) { $this->line($row); } return false; } $this->info("cron نصب شد:\n{$line}"); return true; } private function currentCrontab(): string { exec('crontab -l 2>/dev/null', $lines, $code); if ($code !== 0) { return ''; } return implode("\n", $lines); } private function crontabHasLine(string $crontab, string $marker): bool { if ($crontab === '') { return false; } foreach (preg_split('/\R/u', $crontab) ?: [] as $row) { $row = trim((string) $row); if ($row === '' || str_starts_with($row, '#')) { continue; } if (str_contains($row, $marker)) { return true; } } return false; } }