PluginProbe ʕ •ᴥ•ʔ
Download Manager / 3.3.63
Download Manager v3.3.63
3.3.63 3.3.62 3.3.61 3.3.60 3.3.59 3.3.58 3.3.57 3.3.56 trunk 2.1.3 2.3.0 2.5.96 2.5.97 2.6.2 2.6.96 2.8.3 2.9.99 3.0.4 3.1.05 3.1.07 3.1.08 3.1.11 3.1.12 3.1.14 3.1.17 3.1.18 3.1.22 3.1.23 3.1.24 3.1.25 3.1.26 3.1.27 3.1.28 3.2.04 3.2.13 3.2.14 3.2.16 3.2.18 3.2.19 3.2.21 3.2.22 3.2.23 3.2.24 3.2.25 3.2.27 3.2.28 3.2.29 3.2.30 3.2.31 3.2.32 3.2.33 3.2.34 3.2.35 3.2.37 3.2.38 3.2.39 3.2.40 3.2.41 3.2.42 3.2.43 3.2.44 3.2.45 3.2.46 3.2.47 3.2.48 3.2.49 3.2.50 3.2.51 3.2.52 3.2.53 3.2.54 3.2.55 3.2.56 3.2.57 3.2.58 3.2.59 3.2.60 3.2.61 3.2.63 3.2.64 3.2.65 3.2.66 3.2.67 3.2.68 3.2.69 3.2.70 3.2.71 3.2.72 3.2.73 3.2.74 3.2.75 3.2.76 3.2.77 3.2.78 3.2.79 3.2.80 3.2.81 3.2.82 3.2.83 3.2.84 3.2.85 3.2.86 3.2.87 3.2.88 3.2.89 3.2.90 3.2.91 3.2.92 3.2.93 3.2.94 3.2.95 3.2.96 3.2.97 3.2.98 3.2.99 3.3.00 3.3.01 3.3.02 3.3.03 3.3.04 3.3.05 3.3.06 3.3.07 3.3.08 3.3.09 3.3.10 3.3.11 3.3.12 3.3.13 3.3.14 3.3.15 3.3.16 3.3.17 3.3.18 3.3.19 3.3.20 3.3.21 3.3.22 3.3.23 3.3.24 3.3.25 3.3.26 3.3.27 3.3.28 3.3.29 3.3.30 3.3.31 3.3.32 3.3.33 3.3.34 3.3.35 3.3.36 3.3.37 3.3.38 3.3.39 3.3.40 3.3.41 3.3.42 3.3.43 3.3.44 3.3.45 3.3.46 3.3.47 3.3.48 3.3.49 3.3.50 3.3.51 3.3.52 3.3.53 3.3.54 3.3.55
download-manager / src / __ / CronJobs.php
download-manager / src / __ Last commit date
HTML 1 year ago Jobs 1 day ago views 1 day ago ActivityReport.php 1 day ago Apply.php 6 months ago Cron.php 1 year ago CronJob.php 1 day ago CronJobs.php 1 day ago Crypt.php 2 months ago DownloadStats.php 5 months ago Email.php 1 day ago EmailCron.php 1 year ago FileSystem.php 1 year ago Installer.php 1 day ago Messages.php 1 year ago Query.php 5 months ago Session.php 1 week ago Settings.php 5 years ago SimpleMath.php 5 years ago TempStorage.php 1 week ago Template.php 5 months ago UI.php 7 months ago Updater.php 4 years ago UserAgent.php 2 years ago __.php 2 months ago __MailUI.php 3 years ago
CronJobs.php
550 lines
1 <?php
2 /**
3 * WPDM Cron Jobs Scheduler
4 *
5 * Handles WordPress cron scheduling and job execution triggers.
6 *
7 * @package WPDM\__
8 * @since 7.0.1
9 */
10
11 namespace WPDM\__;
12
13 class CronJobs
14 {
15 /**
16 * Singleton instance
17 *
18 * @var self|null
19 */
20 private static $instance;
21
22 /**
23 * Get singleton instance
24 *
25 * @return self
26 */
27 public static function getInstance(): self
28 {
29 if (self::$instance === null) {
30 self::$instance = new self();
31 }
32 return self::$instance;
33 }
34
35 /**
36 * Constructor - setup cron hooks
37 */
38 public function __construct()
39 {
40 // Register custom cron intervals
41 add_filter('cron_schedules', [$this, 'registerIntervals']);
42
43 // Schedule the main cron event
44 add_action('init', [$this, 'scheduleMainCron']);
45
46 // Register cron action handlers
47 add_action('__wpdm_cron', [$this, 'runScheduledTasks']);
48 add_action('__wpdm_process_jobs', [$this, 'processJobQueue']);
49
50 // HTTP endpoint for external cron triggers
51 add_action('init', [$this, 'handleExternalTrigger']);
52
53 // Admin AJAX handlers
54 add_action('wp_ajax_wpdm_run_cron', [$this, 'ajaxRunCron']);
55 add_action('wp_ajax_wpdm_job_action', [$this, 'ajaxJobAction']);
56 add_action('wp_ajax_wpdm_create_sample_jobs', [$this, 'ajaxCreateSampleJobs']);
57 }
58
59 /**
60 * Register custom cron intervals
61 *
62 * @param array $schedules
63 * @return array
64 */
65 public function registerIntervals(array $schedules): array
66 {
67 $schedules['wpdm_every_minute'] = [
68 'interval' => 60,
69 'display' => __('Every Minute', 'download-manager'),
70 ];
71
72 $schedules['wpdm_every_5_minutes'] = [
73 'interval' => 300,
74 'display' => __('Every 5 Minutes', 'download-manager'),
75 ];
76
77 $schedules['wpdm_every_15_minutes'] = [
78 'interval' => 900,
79 'display' => __('Every 15 Minutes', 'download-manager'),
80 ];
81
82 $schedules['wpdm_every_30_minutes'] = [
83 'interval' => 1800,
84 'display' => __('Every 30 Minutes', 'download-manager'),
85 ];
86
87 $schedules['wpdm_hourly'] = [
88 'interval' => 3600,
89 'display' => __('Hourly', 'download-manager'),
90 ];
91
92 $schedules['wpdm_six_hourly'] = [
93 'interval' => 21600,
94 'display' => __('Every 6 Hours', 'download-manager'),
95 ];
96
97 $schedules['wpdm_daily'] = [
98 'interval' => 86400,
99 'display' => __('Daily', 'download-manager'),
100 ];
101
102 return $schedules;
103 }
104
105 /**
106 * Schedule the main WPDM cron event
107 *
108 * @return void
109 */
110 public function scheduleMainCron(): void
111 {
112 // Main cron for scheduled tasks (cleanup, etc.)
113 if (!wp_next_scheduled('__wpdm_cron')) {
114 wp_schedule_event(time() + 3600, 'wpdm_six_hourly', '__wpdm_cron');
115 }
116
117 // Job queue processor - runs more frequently
118 if (!wp_next_scheduled('__wpdm_process_jobs')) {
119 wp_schedule_event(time() + 60, 'wpdm_every_5_minutes', '__wpdm_process_jobs');
120 }
121 }
122
123 /**
124 * Run scheduled maintenance tasks
125 *
126 * @return void
127 */
128 public function runScheduledTasks(): void
129 {
130 // Clean up old sessions
131 $this->cleanupSessions();
132
133 // Clean up cache files
134 $this->cleanupCache();
135
136 // Clean up old completed/failed jobs
137 CronJob::cleanup(30);
138
139 // Release stale job locks
140 CronJob::releaseStale(30);
141
142 // Allow add-ons to hook into scheduled tasks
143 do_action('wpdm_scheduled_tasks');
144 }
145
146 /**
147 * Process the job queue
148 *
149 * @return void
150 */
151 public function processJobQueue(): void
152 {
153 $cronJob = CronJob::getInstance();
154 $results = $cronJob->executeAll(10);
155
156 if ($results['processed'] > 0) {
157 error_log(sprintf(
158 '[WPDM CronJob] Processed %d jobs: %d succeeded, %d failed',
159 $results['processed'],
160 $results['succeeded'],
161 $results['failed']
162 ));
163 }
164
165 // Allow add-ons to hook into job processing
166 do_action('wpdm_after_process_jobs', $results);
167 }
168
169 /**
170 * Handle external cron trigger via URL
171 *
172 * Supports two endpoints:
173 * - ?wpdm_cron=1&cronkey=XXX - Process job queue
174 * - ?wpdm_task=cleanup&cronkey=XXX - Run specific task
175 *
176 * @return void
177 */
178 public function handleExternalTrigger(): void
179 {
180 $cronKey = wpdm_query_var('cronkey', 'txt');
181
182 // Process job queue
183 if (wpdm_query_var('wpdm_cron', 'int') === 1) {
184 if (!$this->verifyCronKey($cronKey)) {
185 wp_send_json_error(['message' => 'Invalid cron key'], 403);
186 }
187
188 $cronJob = CronJob::getInstance();
189 $results = $cronJob->executeAll(20);
190
191 do_action('wpdm_cron_job');
192
193 wp_send_json_success([
194 'message' => 'Cron executed',
195 'processed' => $results['processed'],
196 'succeeded' => $results['succeeded'],
197 'failed' => $results['failed'],
198 ]);
199 }
200
201 // Run specific task
202 $task = wpdm_query_var('wpdm_task', 'txt');
203 if ($task) {
204 if (!$this->verifyCronKey($cronKey)) {
205 wp_send_json_error(['message' => 'Invalid cron key'], 403);
206 }
207
208 $result = $this->runTask($task);
209 wp_send_json($result);
210 }
211 }
212
213 /**
214 * Run a specific maintenance task
215 *
216 * @param string $task Task name
217 * @return array Result
218 */
219 private function runTask(string $task): array
220 {
221 switch ($task) {
222 case 'cleanup':
223 case 'cleanup_cache':
224 $this->cleanupCache();
225 return ['success' => true, 'message' => 'Cache cleaned'];
226
227 case 'cleanup_sessions':
228 $deleted = $this->cleanupSessions();
229 return ['success' => true, 'message' => "Deleted {$deleted} expired sessions"];
230
231 case 'delete_expired':
232 $deleted = $this->deleteExpiredPackages();
233 return ['success' => true, 'message' => "Deleted {$deleted} expired packages"];
234
235 case 'release_stale':
236 $released = CronJob::releaseStale(30);
237 return ['success' => true, 'message' => "Released {$released} stale locks"];
238
239 case 'cleanup_jobs':
240 $deleted = CronJob::cleanup(30);
241 return ['success' => true, 'message' => "Cleaned up {$deleted} old jobs"];
242
243 default:
244 // Allow custom tasks via filter
245 $result = apply_filters('wpdm_run_cron_task', null, $task);
246 if ($result !== null) {
247 return $result;
248 }
249 return ['success' => false, 'message' => 'Unknown task'];
250 }
251 }
252
253 /**
254 * Verify cron key for external triggers
255 *
256 * @param string $providedKey
257 * @return bool
258 */
259 private function verifyCronKey(string $providedKey): bool
260 {
261 if (empty($providedKey)) {
262 return false;
263 }
264
265 $storedKey = WPDM()->cronJob->cronKey();
266 return hash_equals($storedKey, $providedKey);
267 }
268
269 /**
270 * Clean up expired sessions
271 *
272 * @return int Number of deleted sessions
273 */
274 private function cleanupSessions(): int
275 {
276 global $wpdb;
277
278 $time = time();
279 $deleted = $wpdb->query($wpdb->prepare(
280 "DELETE FROM {$wpdb->prefix}ahm_sessions WHERE `expire` < %d",
281 $time
282 ));
283
284 return $deleted !== false ? $deleted : 0;
285 }
286
287 /**
288 * Clean up cache files
289 *
290 * @return void
291 */
292 private function cleanupCache(): void
293 {
294 if (!(int) get_option('__wpdm_auto_clean_cache', 0)) {
295 return;
296 }
297
298 // Delete zip files in cache
299 FileSystem::deleteFiles(WPDM_CACHE_DIR, false, '.zip');
300
301 // Delete old txt files (older than 1 hour)
302 FileSystem::deleteFiles(WPDM_CACHE_DIR, false, [
303 'filetime' => time() - 3600,
304 'ext' => '.txt'
305 ]);
306 }
307
308 /**
309 * Delete expired packages
310 *
311 * @return int Number of deleted packages
312 */
313 private function deleteExpiredPackages(): int
314 {
315 if (!(int) get_option('__wpdm_delete_expired', 0)) {
316 return 0;
317 }
318
319 global $wpdb;
320
321 $results = $wpdb->get_results($wpdb->prepare(
322 "SELECT post_id, meta_value as expire_date
323 FROM {$wpdb->prefix}postmeta
324 WHERE meta_key = %s AND meta_value <> ''",
325 '__wpdm_expire_date'
326 ));
327
328 $deleted = 0;
329 foreach ($results as $item) {
330 $expireTime = strtotime($item->expire_date);
331 if ($expireTime && $expireTime < time() && get_post_status($item->post_id) === 'publish') {
332 wp_trash_post($item->post_id);
333 $deleted++;
334 }
335 }
336
337 return $deleted;
338 }
339
340 /**
341 * AJAX handler: Run cron manually from admin
342 *
343 * @return void
344 */
345 public function ajaxRunCron(): void
346 {
347 if (!current_user_can('manage_options')) {
348 wp_send_json_error(['message' => 'Permission denied'], 403);
349 }
350
351 check_ajax_referer('wpdm_cron_nonce', 'nonce');
352
353 $cronJob = CronJob::getInstance();
354 $results = $cronJob->executeAll(20);
355
356 wp_send_json_success([
357 'message' => 'Cron executed successfully',
358 'results' => $results,
359 ]);
360 }
361
362 /**
363 * AJAX handler: Job actions (retry, cancel, delete)
364 *
365 * @return void
366 */
367 public function ajaxJobAction(): void
368 {
369 if (!current_user_can('manage_options')) {
370 wp_send_json_error(['message' => 'Permission denied'], 403);
371 }
372
373 check_ajax_referer('wpdm_job_action', 'nonce');
374
375 $action = wpdm_query_var('job_action', 'txt');
376 $jobId = wpdm_query_var('job_id', 'int');
377
378 if (!$jobId) {
379 wp_send_json_error(['message' => 'Invalid job ID']);
380 }
381
382 switch ($action) {
383 case 'retry':
384 $success = CronJob::retry($jobId);
385 $message = $success ? 'Job scheduled for retry' : 'Failed to retry job';
386 break;
387
388 case 'cancel':
389 $success = CronJob::cancel($jobId);
390 $message = $success ? 'Job cancelled' : 'Failed to cancel job';
391 break;
392
393 case 'delete':
394 $success = CronJob::delete($jobId);
395 $message = $success ? 'Job deleted' : 'Failed to delete job';
396 break;
397
398 case 'run_now':
399 $cronJob = CronJob::getInstance();
400 $result = $cronJob->execute($jobId);
401 $success = $result['success'];
402 $message = $result['message'];
403 break;
404
405 default:
406 wp_send_json_error(['message' => 'Invalid action']);
407 return;
408 }
409
410 if ($success) {
411 wp_send_json_success(['message' => $message]);
412 } else {
413 wp_send_json_error(['message' => $message]);
414 }
415 }
416
417 /**
418 * AJAX handler: Create sample jobs for testing
419 *
420 * @return void
421 */
422 public function ajaxCreateSampleJobs(): void
423 {
424 if (!current_user_can('manage_options')) {
425 wp_send_json_error(['message' => 'Permission denied'], 403);
426 }
427
428 check_ajax_referer('wpdm_cron_nonce', 'nonce');
429
430 $jobsCreated = [];
431
432 // 1. Cleanup Job - runs immediately
433 $jobId = CronJob::dispatch(\WPDM\__\Jobs\CleanupJob::class)
434 ->withData([
435 'cleanup_stats' => false,
436 'note' => 'Sample cleanup job'
437 ])
438 ->onQueue('maintenance')
439 ->priority(5)
440 ->unique('sample_cleanup_' . date('Y-m-d'))
441 ->create();
442
443 if ($jobId) {
444 $jobsCreated[] = "CleanupJob #{$jobId}";
445 }
446
447 // 2. Send Email Job - delayed by 5 minutes
448 $jobId = CronJob::dispatch(\WPDM\__\Jobs\SendEmailJob::class)
449 ->withData([
450 'to' => get_option('admin_email'),
451 'subject' => 'WPDM Test Email - ' . date('Y-m-d H:i:s'),
452 'message' => '<h2>Hello!</h2><p>This is a test email from the WPDM Cron Job System.</p><p>If you received this email, the job queue is working correctly!</p>',
453 'from_name' => get_bloginfo('name'),
454 ])
455 ->onQueue('emails')
456 ->priority(8)
457 ->delay(300) // 5 minutes
458 ->attempts(2)
459 ->unique('sample_email_' . date('Y-m-d-H'))
460 ->create();
461
462 if ($jobId) {
463 $jobsCreated[] = "SendEmailJob #{$jobId} (delayed 5 min)";
464 }
465
466 // 3. Delete Expired Job - scheduled for 1 hour later
467 $jobId = CronJob::dispatch(\WPDM\__\Jobs\DeleteExpiredJob::class)
468 ->withData([
469 'permanent_delete' => false,
470 'notify_admin' => true,
471 'note' => 'Sample expired packages check'
472 ])
473 ->onQueue('maintenance')
474 ->priority(3)
475 ->delay(3600) // 1 hour
476 ->unique('sample_delete_expired_' . date('Y-m-d'))
477 ->create();
478
479 if ($jobId) {
480 $jobsCreated[] = "DeleteExpiredJob #{$jobId} (delayed 1 hour)";
481 }
482
483 if (count($jobsCreated) > 0) {
484 wp_send_json_success([
485 'message' => sprintf(
486 'Created %d sample jobs: %s',
487 count($jobsCreated),
488 implode(', ', $jobsCreated)
489 ),
490 'jobs' => $jobsCreated,
491 ]);
492 } else {
493 wp_send_json_error([
494 'message' => 'No jobs created. They may already exist (duplicate unique codes).',
495 ]);
496 }
497 }
498
499 /**
500 * Get the cron URL for external triggers
501 *
502 * @param string $task Optional specific task
503 * @return string
504 */
505 public static function getCronUrl(string $task = ''): string
506 {
507 $cronKey = WPDM()->cronJob->cronKey();
508 $params = ['cronkey' => $cronKey];
509
510 if ($task) {
511 $params['wpdm_task'] = $task;
512 } else {
513 $params['wpdm_cron'] = 1;
514 }
515
516 return add_query_arg($params, home_url('/'));
517 }
518
519 /**
520 * Check if WordPress cron is disabled
521 *
522 * @return bool
523 */
524 public static function isWpCronDisabled(): bool
525 {
526 return defined('DISABLE_WP_CRON') && DISABLE_WP_CRON;
527 }
528
529 /**
530 * Get status of scheduled cron events
531 *
532 * @return array
533 */
534 public static function getScheduledEvents(): array
535 {
536 return [
537 '__wpdm_cron' => [
538 'next_run' => wp_next_scheduled('__wpdm_cron'),
539 'interval' => 'wpdm_six_hourly',
540 'description' => 'Scheduled maintenance tasks',
541 ],
542 '__wpdm_process_jobs' => [
543 'next_run' => wp_next_scheduled('__wpdm_process_jobs'),
544 'interval' => 'wpdm_every_5_minutes',
545 'description' => 'Job queue processor',
546 ],
547 ];
548 }
549 }
550