enabled=0|1 cron=<5 fields|array_start|array_stop|empty> // log_enabled=0|1 // POST batch= // // RESPONSE // {"ok":true,"error":null} // {"ok":false,"error":"POST only"|"Invalid id"|"Invalid cron expression" // |"Failed to write schedule"} // // DEPENDS ON // include/scheduler.php vv_schedule_update(), vv_schedule_update_batch(), // vv_cron_rebuild() // varaverk.cron generated output — never edited directly // ═══════════════════════════════════════════════════════════════════════════════════════════════ header('Content-Type: application/json'); require_once dirname(__DIR__) . '/include/scheduler.php'; if ($_SERVER['REQUEST_METHOD'] !== 'POST') { echo json_encode(['ok' => false, 'error' => 'POST only']); exit; } // Both values below are interpolated into the generated crontab by vv_cron_rebuild(), so // neither may contain a quote, a shell metacharacter, or a newline. function vv_sched_id_valid(string $id): bool { return $id !== '' && !str_contains($id, '..') && (bool)preg_match('/^[A-Za-z0-9_.\-\/]+\.sh$/', $id); } // Five whitespace-separated fields of cron-safe characters only. \s matches newline, so the // field-count pattern alone would accept a value carrying a second crontab line. function vv_sched_cron_valid(string $cron): bool { if (in_array($cron, ['array_start', 'array_stop'], true)) return true; if (!preg_match('/^[0-9A-Za-z*,\-\/ ]+$/', $cron)) return false; return (bool)preg_match('/^(\S+ +){4}\S+$/', $cron); } // Batch save — all entries in one load/write/rebuild cycle if (!empty($_POST['batch'])) { $entries = json_decode($_POST['batch'], true) ?: []; $clean = []; foreach ($entries as $e) { $id = trim($e['id'] ?? ''); $cron = trim($e['cron'] ?? ''); if (!vv_sched_id_valid($id)) continue; if ($cron && !vv_sched_cron_valid($cron)) $cron = ''; $clean[] = [ 'id' => $id, 'enabled' => ($e['enabled'] ?? '0') === '1', 'cron' => $cron, 'log_enabled' => ($e['log_enabled'] ?? '0') === '1', ]; } $ok = vv_schedule_update_batch($clean); echo json_encode(['ok' => $ok, 'error' => $ok ? null : 'Failed to write schedule']); exit; } $id = trim($_POST['id'] ?? ''); $enabled = ($_POST['enabled'] ?? '0') === '1'; $cron = trim($_POST['cron'] ?? ''); $log_enabled = ($_POST['log_enabled'] ?? '0') === '1'; if (!vv_sched_id_valid($id)) { echo json_encode(['ok' => false, 'error' => 'Invalid id']); exit; } // 5 cron fields, or a known event trigger, or empty if ($cron && !vv_sched_cron_valid($cron)) { echo json_encode(['ok' => false, 'error' => 'Invalid cron expression']); exit; } $ok = vv_schedule_update($id, $enabled, $cron, $log_enabled); echo json_encode(['ok' => $ok, 'error' => $ok ? null : 'Failed to write schedule']);