'Method not allowed']); exit; } $input = json_decode(file_get_contents('php://input'), true); $username = trim($input['username'] ?? ''); $filepath = trim($input['filepath'] ?? ''); $content = $input['content'] ?? ''; // Validate username if (!preg_match('/^[a-z0-9]{3,32}$/', $username)) { http_response_code(400); echo json_encode(['error' => 'Invalid username']); exit; } // Validate filepath — only allow simple filenames, no directory traversal $filepath = basename($filepath); if (empty($filepath)) { http_response_code(400); echo json_encode(['error' => 'Invalid filepath']); exit; } // Allowed extensions $allowed = ['php','html','htm','css','js','json','txt','xml','svg']; $ext = strtolower(pathinfo($filepath, PATHINFO_EXTENSION)); if (!in_array($ext, $allowed)) { http_response_code(400); echo json_encode(['error' => "File type .{$ext} not allowed in editor"]); exit; } // Check user exists $db = new PDO('sqlite:/data/db/platform.sqlite'); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt = $db->prepare('SELECT id FROM users WHERE username = ?'); $stmt->execute([$username]); if (!$stmt->fetch()) { http_response_code(404); echo json_encode(['error' => 'User not found']); exit; } $htdocs = "/data/sites/{$username}/htdocs"; $dest = "{$htdocs}/{$filepath}"; // Write the file if (file_put_contents($dest, $content) === false) { http_response_code(500); echo json_encode(['error' => 'Failed to write file']); exit; } // Update files table $stmt = $db->prepare(' INSERT INTO files (username, filepath, updated_at) VALUES (?, ?, datetime("now")) ON CONFLICT(username, filepath) DO UPDATE SET updated_at=datetime("now") '); $stmt->execute([$username, $filepath]); echo json_encode([ 'success' => true, 'username' => $username, 'filepath' => $filepath, 'message' => 'File saved successfully' ]);