在Moodle定时任务中实现跨服务器向WordPress安全传输数据
Hey, I’ve tackled similar cross-server sync tasks before, so here’s a robust, secure solution tailored for your setup—perfect for unlimited data volumes, and built to slot right into your existing Moodle cron framework:
1. First: Lock Down Cross-Site Authentication
Since your Moodle and WordPress are on separate servers, we need to make sure only legitimate requests from Moodle get processed by WordPress. API key + HMAC signature is way more secure than a plain API key, so we’ll go with that.
Step 1: Set Up the WordPress Receive Endpoint
Add this to your WordPress theme’s functions.php or a custom plugin (custom plugins are better for maintainability):
add_action('rest_api_init', function () { register_rest_route('moodle-sync/v1', '/receive-data', array( 'methods' => 'POST', 'callback' => 'moodle_sync_receive_data', 'permission_callback' => function ($request) { // Pull your pre-configured API key (store this in WP admin settings, not hardcoded!) $api_key = get_option('moodle_sync_api_key'); $signature = $request->get_header('X-Signature'); $timestamp = $request->get_header('X-Timestamp'); // Block replay attacks: only accept requests from the last 5 minutes if (abs(time() - $timestamp) > 300) { return new WP_Error('invalid_timestamp', 'Request timed out', array('status' => 403)); } // Generate expected signature using HMAC-SHA256 $request_body = $request->get_body(); $expected_signature = hash_hmac('sha256', $timestamp . $request_body, $api_key); if ($signature !== $expected_signature) { return new WP_Error('invalid_signature', 'Signature verification failed', array('status' => 403)); } return true; } )); }); function moodle_sync_receive_data($request) { $data = $request->get_json_params(); // Replace this with your actual data handling logic (e.g., create posts, update user data) $post_args = array( 'post_title' => sanitize_text_field($data['title']), 'post_content' => wp_kses_post($data['content']), 'post_status' => 'publish', 'post_type' => 'post' ); $post_id = wp_insert_post($post_args); return $post_id ? array('status' => 'success', 'post_id' => $post_id) : new WP_Error('save_failed', 'Failed to save data', array('status' => 500)); }
Don’t forget to add an admin setting in WordPress to store your API key (use add_settings_field() and friends) instead of hardcoding it.
Step 2: Moodle Side Signature & Request Setup
In your Moodle cron task’s PHP code, start with generating the secure signature and preparing your data:
// Configuration - store these in Moodle's config.php as constants for security define('WP_SYNC_API_KEY', 'your-strong-unique-api-key-here'); define('WP_RESYNC_ENDPOINT', 'https://your-wp-site.com/wp-json/moodle-sync/v1/receive-data'); // Fetch data from Moodle (customize this to pull whatever you need to sync) function get_moodle_sync_data() { global $DB; // Example: pull unsynced course updates return $DB->get_records('course', array('timemodified' => time() - 86400), '', 'id, fullname, summary'); } $moodle_data = get_moodle_sync_data(); $timestamp = time();
2. Handle Unlimited Data Volumes
Since data can be huge, we can’t send everything in one request. Split it into batches, or use streaming for files.
Batch Processing for Structured Data
$batch_size = 100; // Adjust based on your server capacity $total_batches = ceil(count($moodle_data) / $batch_size); for ($batch_num = 0; $batch_num < $total_batches; $batch_num++) { $batch = array_slice($moodle_data, $batch_num * $batch_size, $batch_size); $json_payload = json_encode($batch); // Regenerate signature for each unique payload $signature = hash_hmac('sha256', $timestamp . $json_payload, WP_SYNC_API_KEY); // Send request $response = send_sync_request($json_payload, $timestamp, $signature); // Log results (Moodle's mtrace works great for cron logs) if ($response['status'] === 'success') { mtrace("Batch $batch_num synced successfully"); // Mark these records as synced in Moodle foreach ($batch as $record) { $DB->set_field('course', 'synced', 1, array('id' => $record->id)); } } else { mtrace("Batch $batch_num failed: " . $response['message']); // Optional: add retry logic here for failed batches } } // Reusable request function with SSL hardening function send_sync_request($payload, $timestamp, $signature) { $ch = curl_init(WP_RESYNC_ENDPOINT); curl_setopt_array($ch, array( CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payload, CURLOPT_HTTPHEADER => array( 'Content-Type: application/json', "X-Timestamp: $timestamp", "X-Signature: $signature" ), // Enforce SSL security (never disable these in production!) CURLOPT_SSL_VERIFYPEER => true, CURLOPT_SSL_VERIFYHOST => 2 )); $response_body = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($http_code === 200) { return json_decode($response_body, true); } else { return array( 'status' => 'error', 'message' => "HTTP $http_code: " . substr($response_body, 0, 200) // Truncate long errors ); } }
Streaming Large Files (e.g., Moodle Attachments)
If you need to sync files, use multipart/form-data and include a file hash for integrity checks:
// Example: Sync a Moodle file to WordPress media library $file_path = '/path/to/moodle/user/file.pdf'; $file_hash = hash_file('sha256', $file_path); $timestamp = time(); $signature = hash_hmac('sha256', $timestamp . $file_hash, WP_SYNC_API_KEY); $ch = curl_init(WP_RESYNC_ENDPOINT); curl_setopt_array($ch, array( CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => array( 'file' => new CURLFile($file_path), 'file_hash' => $file_hash, 'metadata' => json_encode(array('source' => 'Moodle')) ), CURLOPT_HTTPHEADER => array( "X-Timestamp: $timestamp", "X-Signature: $signature" ), CURLOPT_SSL_VERIFYPEER => true, CURLOPT_SSL_VERIFYHOST => 2 )); $response = curl_exec($ch); // Update WordPress endpoint to handle file uploads and verify $file_hash
3. Integrate with Moodle Cron Task
Since you already have the cron framework set up, just drop the above logic into your task’s execute() method:
class local_sync_to_wp_task extends core\task\scheduled_task { public function get_name() { return get_string('synctowp', 'local_syncplugin'); } public function execute() { mtrace("Starting Moodle to WordPress sync..."); // Place all the sync logic here (data fetching, batch processing, requests) mtrace("Sync completed"); } }
4. Critical Security & Reliability Tips
- Rotate API Keys: Change your API key every few months to reduce risk of compromise.
- Idempotency: Add a unique
sync_idto each record so WordPress doesn’t create duplicates if a batch is retried. - Logging: Keep detailed logs in both Moodle (use
mtraceor Moodle’s logging API) and WordPress (useerror_log()or a logging plugin). - Retry Logic: For failed batches, implement exponential backoff (e.g., wait 1min, then 2min, then 4min) instead of immediate retries.
- Validate Input: Sanitize all data in both Moodle (before sending) and WordPress (before processing) to prevent XSS/SQL injection.
内容的提问来源于stack exchange,提问作者CloudJake

