安全修复: - sync.php: 删除verify_web_password端点,禁止PHP自验证密码 - core.php: validateWebAccess大额交易密码验证改为检查web_login_verified(Java验证结果) - 密码验证强制走web_login_request流程 其他: - land_api.php: handleAckAdminChanges支持GET参数ids(避免POST Content-Type问题)
1108 lines
40 KiB
PHP
1108 lines
40 KiB
PHP
<?php
|
||
/**
|
||
* 领地系统API - 接收Java端领地数据 + 管理面板 + 玩家端
|
||
* POST: Java端推送领地数据
|
||
* GET: admin/玩家面板读取领地数据
|
||
*/
|
||
header('Content-Type: application/json; charset=utf-8');
|
||
error_reporting(E_ERROR | E_PARSE);
|
||
|
||
try {
|
||
// ★ 加载core.php(与sync.php相同的加载方式)
|
||
$coreFile = dirname(__DIR__) . '/core.php';
|
||
if (!file_exists($coreFile)) {
|
||
$coreFile = dirname(__DIR__) . '/plugin/core.php';
|
||
}
|
||
require_once $coreFile;
|
||
|
||
$action = $_GET['action'] ?? $_POST['action'] ?? '';
|
||
$secret = $_GET['secret'] ?? $_POST['secret'] ?? '';
|
||
$method = $_SERVER['REQUEST_METHOD'];
|
||
|
||
// ===== 验证 =====
|
||
// 三种认证方式:
|
||
// 1. Java端推送: POST + secret
|
||
// 2. 管理面板: GET/POST + admin_token (admin.php已登录的session)
|
||
// 3. 玩家端: GET + player_token
|
||
$playerName = '';
|
||
$isAdmin = false;
|
||
|
||
// 同步类action只接受secret验证(Java端推送)
|
||
$syncActions = ['sync_lands', 'sync_shop', 'sync_permissions'];
|
||
// 管理面板action:支持admin_token或secret
|
||
$adminActions = ['list_lands', 'list_shop', 'get_config', 'update_config', 'delete_land', 'update_land_owner', 'delete_shop_item'];
|
||
// 玩家端action:需要token
|
||
$playerActions = ['my_lands', 'land_detail', 'add_visitor', 'remove_visitor', 'list_visitors', 'land_shop', 'buy_permission'];
|
||
// ★ 玩家端权限操作action
|
||
$playerPermActions = ['update_visitor_perm', 'get_visitor_perm'];
|
||
// ★ 成员独立权限操作action(领地所有者编辑成员权限)
|
||
$memberPermActions = ['get_member_perms', 'update_member_perm', 'clear_member_perm'];
|
||
// ★ Java端轮询PHP管理员变更
|
||
$syncFromPhpActions = ['poll_admin_changes', 'ack_admin_changes'];
|
||
|
||
if (in_array($action, $syncActions) || in_array($action, $syncFromPhpActions)) {
|
||
// 同步类:必须有secret
|
||
if (!validateSecret($secret)) {
|
||
echo json_encode(['success' => false, 'error' => 'invalid secret']);
|
||
exit;
|
||
}
|
||
} elseif (in_array($action, $adminActions)) {
|
||
// 管理面板:验证admin_token或secret
|
||
$adminToken = $_GET['admin_token'] ?? $_POST['admin_token'] ?? '';
|
||
if (!empty($adminToken)) {
|
||
// 用admin_token验证(admin.php的登录态)
|
||
$adminInfo = validateTokenSilent($adminToken);
|
||
if (!$adminInfo) {
|
||
echo json_encode(['success' => false, 'error' => '管理员认证失败', 'needLogin' => true]);
|
||
exit;
|
||
}
|
||
$isAdmin = true;
|
||
} elseif (!validateSecret($secret)) {
|
||
// 没有admin_token,尝试secret
|
||
echo json_encode(['success' => false, 'error' => '需要管理员认证']);
|
||
exit;
|
||
}
|
||
} elseif (in_array($action, $playerActions) || in_array($action, $playerPermActions) || in_array($action, $memberPermActions)) {
|
||
// 玩家端:需要token
|
||
$token = $_GET['token'] ?? '';
|
||
if (empty($token)) {
|
||
echo json_encode(['success' => false, 'error' => '需要登录', 'needLogin' => true]);
|
||
exit;
|
||
}
|
||
$tokenInfo = validateTokenSilent($token);
|
||
if (!$tokenInfo) {
|
||
echo json_encode(['success' => false, 'error' => 'token无效或已过期', 'needLogin' => true]);
|
||
exit;
|
||
}
|
||
$playerName = is_array($tokenInfo) ? $tokenInfo['player'] : $tokenInfo;
|
||
} else {
|
||
// 未知action:默认放行(部分公开GET读取)
|
||
if ($method === 'POST' && !validateSecret($secret)) {
|
||
echo json_encode(['success' => false, 'error' => 'invalid secret']);
|
||
exit;
|
||
}
|
||
}
|
||
|
||
$db = getDB();
|
||
|
||
// 建表
|
||
initLandTables($db);
|
||
|
||
switch ($action) {
|
||
// ===== Java端推送领地数据 =====
|
||
case 'sync_lands':
|
||
handleSyncLands($db, $_POST);
|
||
break;
|
||
|
||
// ===== Java端推送权限商店数据 =====
|
||
case 'sync_shop':
|
||
handleSyncShop($db, $_POST);
|
||
break;
|
||
|
||
// ===== Java端推送访客权限数据 =====
|
||
case 'sync_permissions':
|
||
handleSyncPermissions($db, $_POST);
|
||
break;
|
||
|
||
// ===== 管理面板:获取所有领地 =====
|
||
case 'list_lands':
|
||
if ($method !== 'GET') {
|
||
echo json_encode(['success' => false, 'error' => 'GET only']);
|
||
exit;
|
||
}
|
||
handleListLands($db);
|
||
break;
|
||
|
||
// ===== 管理面板:获取权限商店 =====
|
||
case 'list_shop':
|
||
if ($method !== 'GET') {
|
||
echo json_encode(['success' => false, 'error' => 'GET only']);
|
||
exit;
|
||
}
|
||
handleListShop($db);
|
||
break;
|
||
|
||
// ===== 管理面板:获取配置 =====
|
||
case 'get_config':
|
||
handleGetConfig($db);
|
||
break;
|
||
|
||
// ===== 管理面板:更新配置 =====
|
||
case 'update_config':
|
||
handleUpdateConfig($db, $_POST);
|
||
break;
|
||
|
||
// ===== 管理面板:删除领地 =====
|
||
case 'delete_land':
|
||
handleDeleteLand($db, $_POST);
|
||
break;
|
||
|
||
// ===== 管理面板:更新领地所有者 =====
|
||
case 'update_land_owner':
|
||
handleUpdateLandOwner($db, $_POST);
|
||
break;
|
||
|
||
// ===== 管理面板:删除权限商品 =====
|
||
case 'delete_shop_item':
|
||
handleDeleteShopItem($db, $_POST);
|
||
break;
|
||
|
||
// ===== 玩家端:我拥有的领地 =====
|
||
case 'my_lands':
|
||
handleMyLands($db, $playerName);
|
||
break;
|
||
|
||
// ===== 玩家端:领地详情(含访客列表)=====
|
||
case 'land_detail':
|
||
handleLandDetail($db, $playerName, $_GET['name'] ?? '');
|
||
break;
|
||
|
||
// ===== 玩家端:添加访客 =====
|
||
case 'add_visitor':
|
||
if ($method !== 'GET' && $method !== 'POST') {
|
||
echo json_encode(['success' => false, 'error' => 'GET/POST only']);
|
||
exit;
|
||
}
|
||
$req = $method === 'POST' ? $_POST : $_GET;
|
||
handleAddVisitor($db, $playerName, $req);
|
||
break;
|
||
|
||
// ===== 玩家端:移除访客 =====
|
||
case 'remove_visitor':
|
||
if ($method !== 'GET' && $method !== 'POST') {
|
||
echo json_encode(['success' => false, 'error' => 'GET/POST only']);
|
||
exit;
|
||
}
|
||
$req = $method === 'POST' ? $_POST : $_GET;
|
||
handleRemoveVisitor($db, $playerName, $req);
|
||
break;
|
||
|
||
// ===== 玩家端:访客列表 =====
|
||
case 'list_visitors':
|
||
handleListVisitors($db, $_GET['name'] ?? '');
|
||
break;
|
||
|
||
// ===== 玩家端:领地商店(购买访客权限)=====
|
||
case 'land_shop':
|
||
handleLandShop($db, $_GET['name'] ?? '');
|
||
break;
|
||
|
||
// ===== 玩家端:获取访客权限 =====
|
||
case 'get_visitor_perm':
|
||
handleGetVisitorPerm($db, $playerName, $_GET['land'] ?? '');
|
||
break;
|
||
|
||
// ===== 玩家端:更新访客权限 =====
|
||
case 'update_visitor_perm':
|
||
if ($method !== 'POST') {
|
||
echo json_encode(['success' => false, 'error' => 'POST only']);
|
||
exit;
|
||
}
|
||
handleUpdateVisitorPerm($db, $playerName, $_POST);
|
||
break;
|
||
|
||
// ===== 成员独立权限:获取成员权限列表 =====
|
||
case 'get_member_perms':
|
||
handleGetMemberPerms($db, $playerName, $_GET['land'] ?? '');
|
||
break;
|
||
|
||
// ===== 成员独立权限:更新单个权限 =====
|
||
case 'update_member_perm':
|
||
if ($method !== 'POST') {
|
||
echo json_encode(['success' => false, 'error' => 'POST only']);
|
||
exit;
|
||
}
|
||
handleUpdateMemberPerm($db, $playerName, $_POST);
|
||
break;
|
||
|
||
// ===== 成员独立权限:清除所有自定义权限 =====
|
||
case 'clear_member_perm':
|
||
if ($method !== 'POST') {
|
||
echo json_encode(['success' => false, 'error' => 'POST only']);
|
||
exit;
|
||
}
|
||
handleClearMemberPerm($db, $playerName, $_POST);
|
||
break;
|
||
|
||
// ===== Java端轮询PHP管理员变更 =====
|
||
case 'poll_admin_changes':
|
||
handlePollAdminChanges($db, $_GET);
|
||
break;
|
||
|
||
// ===== Java端确认已处理变更 =====
|
||
case 'ack_admin_changes':
|
||
handleAckAdminChanges($db, $_POST);
|
||
break;
|
||
|
||
default:
|
||
echo json_encode(['success' => false, 'error' => 'unknown action']);
|
||
}
|
||
} catch (\Throwable $e) {
|
||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||
}
|
||
|
||
// ==================== 函数 ====================
|
||
|
||
function initLandTables($db) {
|
||
$db->exec("CREATE TABLE IF NOT EXISTS web_area_lands (
|
||
id INTEGER PRIMARY KEY,
|
||
name TEXT UNIQUE NOT NULL,
|
||
owner TEXT DEFAULT '',
|
||
world TEXT DEFAULT '',
|
||
x1 INTEGER DEFAULT 0, z1 INTEGER DEFAULT 0,
|
||
x2 INTEGER DEFAULT 0, z2 INTEGER DEFAULT 0,
|
||
y_min INTEGER DEFAULT 0, y_max INTEGER DEFAULT 255,
|
||
area_size INTEGER DEFAULT 0,
|
||
created_at INTEGER DEFAULT 0,
|
||
synced_at INTEGER DEFAULT 0
|
||
)");
|
||
|
||
$db->exec("CREATE TABLE IF NOT EXISTS web_area_shop (
|
||
id INTEGER PRIMARY KEY,
|
||
land_id INTEGER NOT NULL,
|
||
land_name TEXT DEFAULT '',
|
||
seller TEXT NOT NULL,
|
||
permission TEXT DEFAULT 'visitor',
|
||
price INTEGER DEFAULT 0,
|
||
duration INTEGER DEFAULT 86400,
|
||
status TEXT DEFAULT 'active',
|
||
buyer TEXT DEFAULT '',
|
||
bought_at INTEGER DEFAULT 0,
|
||
created_at INTEGER DEFAULT 0,
|
||
synced_at INTEGER DEFAULT 0
|
||
)");
|
||
|
||
$db->exec("CREATE TABLE IF NOT EXISTS web_area_config (
|
||
key TEXT PRIMARY KEY,
|
||
value TEXT DEFAULT ''
|
||
)");
|
||
|
||
// ★ 访客权限表(Java端同步过来)
|
||
$db->exec("CREATE TABLE IF NOT EXISTS web_area_permissions (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
land_id INTEGER NOT NULL,
|
||
land_name TEXT DEFAULT '',
|
||
player_name TEXT NOT NULL,
|
||
role TEXT NOT NULL DEFAULT 'visitor',
|
||
permissions TEXT DEFAULT '',
|
||
granted_at INTEGER DEFAULT 0,
|
||
expires_at INTEGER DEFAULT 0,
|
||
synced_at INTEGER DEFAULT 0,
|
||
UNIQUE(land_id, player_name)
|
||
)");
|
||
|
||
// ★ 管理员变更队列表(PHP→Java同步)
|
||
$db->exec("CREATE TABLE IF NOT EXISTS web_admin_changes (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
change_type TEXT NOT NULL,
|
||
target_id TEXT NOT NULL,
|
||
target_name TEXT DEFAULT '',
|
||
change_data TEXT DEFAULT '',
|
||
created_at INTEGER DEFAULT 0,
|
||
acknowledged INTEGER DEFAULT 0,
|
||
acked_at INTEGER DEFAULT 0
|
||
)");
|
||
|
||
// ★ 领地所有者变更表(记录PHP端修改的所有者变更)
|
||
$db->exec("CREATE TABLE IF NOT EXISTS web_land_owner_changes (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
land_id INTEGER NOT NULL,
|
||
land_name TEXT NOT NULL,
|
||
old_owner TEXT DEFAULT '',
|
||
new_owner TEXT NOT NULL,
|
||
created_at INTEGER DEFAULT 0,
|
||
synced INTEGER DEFAULT 0
|
||
)");
|
||
}
|
||
|
||
function handleSyncLands($db, $post) {
|
||
$lands = json_decode($post['lands'] ?? '[]', true);
|
||
if (!is_array($lands)) {
|
||
echo json_encode(['success' => false, 'error' => 'invalid lands data']);
|
||
return;
|
||
}
|
||
|
||
$now = time();
|
||
$stmt = $db->prepare("INSERT OR REPLACE INTO web_area_lands
|
||
(id, name, owner, world, x1, z1, x2, z2, y_min, y_max, area_size, created_at, synced_at)
|
||
VALUES (:id, :name, :owner, :world, :x1, :z1, :x2, :z2, :ymin, :ymax, :size, :created, :synced)");
|
||
|
||
foreach ($lands as $land) {
|
||
$stmt->bindValue(':id', (int)($land['id'] ?? 0), SQLITE3_INTEGER);
|
||
$stmt->bindValue(':name', $land['name'] ?? '', SQLITE3_TEXT);
|
||
$stmt->bindValue(':owner', $land['owner'] ?? '', SQLITE3_TEXT);
|
||
$stmt->bindValue(':world', $land['world'] ?? '', SQLITE3_TEXT);
|
||
$stmt->bindValue(':x1', (int)($land['x1'] ?? 0), SQLITE3_INTEGER);
|
||
$stmt->bindValue(':z1', (int)($land['z1'] ?? 0), SQLITE3_INTEGER);
|
||
$stmt->bindValue(':x2', (int)($land['x2'] ?? 0), SQLITE3_INTEGER);
|
||
$stmt->bindValue(':z2', (int)($land['z2'] ?? 0), SQLITE3_INTEGER);
|
||
$stmt->bindValue(':ymin', (int)($land['y_min'] ?? 0), SQLITE3_INTEGER);
|
||
$stmt->bindValue(':ymax', (int)($land['y_max'] ?? 255), SQLITE3_INTEGER);
|
||
$stmt->bindValue(':size', (int)($land['area_size'] ?? 0), SQLITE3_INTEGER);
|
||
$stmt->bindValue(':created', (int)($land['created_at'] ?? 0), SQLITE3_INTEGER);
|
||
$stmt->bindValue(':synced', $now, SQLITE3_INTEGER);
|
||
$stmt->execute();
|
||
}
|
||
|
||
echo json_encode(['success' => true, 'count' => count($lands)]);
|
||
}
|
||
|
||
function handleSyncShop($db, $post) {
|
||
$items = json_decode($post['items'] ?? '[]', true);
|
||
if (!is_array($items)) {
|
||
echo json_encode(['success' => false, 'error' => 'invalid shop data']);
|
||
return;
|
||
}
|
||
|
||
$now = time();
|
||
$stmt = $db->prepare("INSERT OR REPLACE INTO web_area_shop
|
||
(id, land_id, land_name, seller, permission, price, duration, status, buyer, bought_at, created_at, synced_at)
|
||
VALUES (:id, :land_id, :land_name, :seller, :perm, :price, :dur, :status, :buyer, :bought, :created, :synced)");
|
||
|
||
foreach ($items as $item) {
|
||
$stmt->bindValue(':id', (int)($item['id'] ?? 0), SQLITE3_INTEGER);
|
||
$stmt->bindValue(':land_id', (int)($item['land_id'] ?? 0), SQLITE3_INTEGER);
|
||
$stmt->bindValue(':land_name', $item['land_name'] ?? '', SQLITE3_TEXT);
|
||
$stmt->bindValue(':seller', $item['seller'] ?? '', SQLITE3_TEXT);
|
||
$stmt->bindValue(':perm', $item['permission'] ?? 'visitor', SQLITE3_TEXT);
|
||
$stmt->bindValue(':price', (int)($item['price'] ?? 0), SQLITE3_INTEGER);
|
||
$stmt->bindValue(':dur', (int)($item['duration'] ?? 86400), SQLITE3_INTEGER);
|
||
$stmt->bindValue(':status', $item['status'] ?? 'active', SQLITE3_TEXT);
|
||
$stmt->bindValue(':buyer', $item['buyer'] ?? '', SQLITE3_TEXT);
|
||
$stmt->bindValue(':bought', (int)($item['bought_at'] ?? 0), SQLITE3_INTEGER);
|
||
$stmt->bindValue(':created', (int)($item['created_at'] ?? 0), SQLITE3_INTEGER);
|
||
$stmt->bindValue(':synced', $now, SQLITE3_INTEGER);
|
||
$stmt->execute();
|
||
}
|
||
|
||
echo json_encode(['success' => true, 'count' => count($items)]);
|
||
}
|
||
|
||
function handleListLands($db) {
|
||
$result = $db->query("SELECT * FROM web_area_lands ORDER BY synced_at DESC");
|
||
$lands = [];
|
||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||
$lands[] = $row;
|
||
}
|
||
echo json_encode(['success' => true, 'lands' => $lands]);
|
||
}
|
||
|
||
function handleListShop($db) {
|
||
$result = $db->query("SELECT * FROM web_area_shop ORDER BY created_at DESC LIMIT 100");
|
||
$items = [];
|
||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||
$items[] = $row;
|
||
}
|
||
echo json_encode(['success' => true, 'items' => $items]);
|
||
}
|
||
|
||
function handleGetConfig($db) {
|
||
$config = [];
|
||
$result = $db->query("SELECT * FROM web_area_config");
|
||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||
$config[$row['key']] = $row['value'];
|
||
}
|
||
echo json_encode(['success' => true, 'config' => $config]);
|
||
}
|
||
|
||
function handleUpdateConfig($db, $post) {
|
||
$key = $post['key'] ?? '';
|
||
$value = $post['value'] ?? '';
|
||
if (empty($key)) {
|
||
echo json_encode(['success' => false, 'error' => 'missing key']);
|
||
return;
|
||
}
|
||
|
||
$stmt = $db->prepare("INSERT OR REPLACE INTO web_area_config (key, value) VALUES (:key, :val)");
|
||
$stmt->bindValue(':key', $key, SQLITE3_TEXT);
|
||
$stmt->bindValue(':val', $value, SQLITE3_TEXT);
|
||
$stmt->execute();
|
||
|
||
echo json_encode(['success' => true]);
|
||
}
|
||
|
||
function handleDeleteLand($db, $post) {
|
||
$name = $post['name'] ?? '';
|
||
if (empty($name)) {
|
||
echo json_encode(['success' => false, 'error' => 'missing name']);
|
||
return;
|
||
}
|
||
|
||
$stmt = $db->prepare("DELETE FROM web_area_lands WHERE name = :name");
|
||
$stmt->bindValue(':name', $name, SQLITE3_TEXT);
|
||
$stmt->execute();
|
||
|
||
echo json_encode(['success' => true]);
|
||
}
|
||
|
||
function handleUpdateLandOwner($db, $post) {
|
||
$name = $post['name'] ?? '';
|
||
$owner = $post['owner'] ?? '';
|
||
if (empty($name)) {
|
||
echo json_encode(['success' => false, 'error' => 'missing name']);
|
||
return;
|
||
}
|
||
|
||
// 获取旧所有者
|
||
$stmt = $db->prepare("SELECT owner FROM web_area_lands WHERE name = :name");
|
||
$stmt->bindValue(':name', $name, SQLITE3_TEXT);
|
||
$result = $stmt->execute();
|
||
$row = $result->fetchArray(SQLITE3_ASSOC);
|
||
$oldOwner = $row ? ($row['owner'] ?? '') : '';
|
||
|
||
// 更新所有者
|
||
$stmt2 = $db->prepare("UPDATE web_area_lands SET owner = :owner WHERE name = :name");
|
||
$stmt2->bindValue(':owner', $owner, SQLITE3_TEXT);
|
||
$stmt2->bindValue(':name', $name, SQLITE3_TEXT);
|
||
$stmt2->execute();
|
||
|
||
// 记录变更(用于同步到Java)
|
||
if ($oldOwner !== $owner) {
|
||
$landId = (int)($post['id'] ?? 0);
|
||
$stmt3 = $db->prepare("INSERT INTO web_land_owner_changes (land_id, land_name, old_owner, new_owner, created_at) VALUES (:lid, :name, :old, :new, :now)");
|
||
$stmt3->bindValue(':lid', $landId, SQLITE3_INTEGER);
|
||
$stmt3->bindValue(':name', $name, SQLITE3_TEXT);
|
||
$stmt3->bindValue(':old', $oldOwner, SQLITE3_TEXT);
|
||
$stmt3->bindValue(':new', $owner, SQLITE3_TEXT);
|
||
$stmt3->bindValue(':now', time(), SQLITE3_INTEGER);
|
||
$stmt3->execute();
|
||
|
||
// 同时添加到变更队列
|
||
$stmt4 = $db->prepare("INSERT INTO web_admin_changes (change_type, target_id, target_name, change_data, created_at) VALUES ('owner_change', :id, :name, :data, :now)");
|
||
$stmt4->bindValue(':id', (int)($post['id'] ?? 0), SQLITE3_INTEGER);
|
||
$stmt4->bindValue(':name', $name, SQLITE3_TEXT);
|
||
$stmt4->bindValue(':data', json_encode(['old_owner' => $oldOwner, 'new_owner' => $owner]), SQLITE3_TEXT);
|
||
$stmt4->bindValue(':now', time(), SQLITE3_INTEGER);
|
||
$stmt4->execute();
|
||
}
|
||
|
||
echo json_encode(['success' => true]);
|
||
}
|
||
|
||
function handleDeleteShopItem($db, $post) {
|
||
$id = (int)($post['id'] ?? 0);
|
||
if ($id <= 0) {
|
||
echo json_encode(['success' => false, 'error' => 'invalid id']);
|
||
return;
|
||
}
|
||
|
||
$stmt = $db->prepare("UPDATE web_area_shop SET status = 'removed' WHERE id = :id");
|
||
$stmt->bindValue(':id', $id, SQLITE3_INTEGER);
|
||
$stmt->execute();
|
||
|
||
echo json_encode(['success' => true]);
|
||
}
|
||
|
||
// ==================== Java端同步:访客权限 ====================
|
||
|
||
function handleSyncPermissions($db, $post) {
|
||
$perms = json_decode($post['permissions'] ?? '[]', true);
|
||
if (!is_array($perms)) {
|
||
echo json_encode(['success' => false, 'error' => 'invalid permissions data']);
|
||
return;
|
||
}
|
||
|
||
$now = time();
|
||
$stmt = $db->prepare("INSERT OR REPLACE INTO web_area_permissions
|
||
(land_id, land_name, player_name, role, permissions, granted_at, expires_at, synced_at)
|
||
VALUES (:land_id, :land_name, :player, :role, :perms, :granted, :expires, :synced)");
|
||
|
||
foreach ($perms as $p) {
|
||
$stmt->bindValue(':land_id', (int)($p['land_id'] ?? 0), SQLITE3_INTEGER);
|
||
$stmt->bindValue(':land_name', $p['land_name'] ?? '', SQLITE3_TEXT);
|
||
$stmt->bindValue(':player', $p['player_name'] ?? '', SQLITE3_TEXT);
|
||
$stmt->bindValue(':role', $p['role'] ?? 'visitor', SQLITE3_TEXT);
|
||
$stmt->bindValue(':perms', $p['permissions'] ?? '', SQLITE3_TEXT);
|
||
$stmt->bindValue(':granted', (int)($p['granted_at'] ?? 0), SQLITE3_INTEGER);
|
||
$stmt->bindValue(':expires', (int)($p['expires_at'] ?? 0), SQLITE3_INTEGER);
|
||
$stmt->bindValue(':synced', $now, SQLITE3_INTEGER);
|
||
$stmt->execute();
|
||
}
|
||
|
||
echo json_encode(['success' => true, 'count' => count($perms)]);
|
||
}
|
||
|
||
// ==================== 玩家端:我拥有的领地 ====================
|
||
|
||
function handleMyLands($db, $playerName) {
|
||
$stmt = $db->prepare("SELECT * FROM web_area_lands WHERE owner = :owner ORDER BY created_at DESC");
|
||
$stmt->bindValue(':owner', $playerName, SQLITE3_TEXT);
|
||
$result = $stmt->execute();
|
||
|
||
$lands = [];
|
||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||
$lands[] = $row;
|
||
}
|
||
|
||
echo json_encode(['success' => true, 'lands' => $lands, 'player' => $playerName]);
|
||
}
|
||
|
||
// ==================== 玩家端:领地详情(含访客) ====================
|
||
|
||
function handleLandDetail($db, $playerName, $landName) {
|
||
if (empty($landName)) {
|
||
echo json_encode(['success' => false, 'error' => '缺少领地名称']);
|
||
return;
|
||
}
|
||
|
||
// 获取领地信息
|
||
$stmt = $db->prepare("SELECT * FROM web_area_lands WHERE name = :name");
|
||
$stmt->bindValue(':name', $landName, SQLITE3_TEXT);
|
||
$result = $stmt->execute();
|
||
$land = $result->fetchArray(SQLITE3_ASSOC);
|
||
|
||
if (!$land) {
|
||
echo json_encode(['success' => false, 'error' => '领地不存在']);
|
||
return;
|
||
}
|
||
|
||
// 权限检查:只有所有者或管理员能查看详情
|
||
if ($land['owner'] !== $playerName) {
|
||
echo json_encode(['success' => false, 'error' => '你不是此领地的所有者']);
|
||
return;
|
||
}
|
||
|
||
// 获取访客列表
|
||
$stmt2 = $db->prepare("SELECT * FROM web_area_permissions WHERE land_id = :land_id ORDER BY granted_at DESC");
|
||
$stmt2->bindValue(':land_id', (int)$land['id'], SQLITE3_INTEGER);
|
||
$result2 = $stmt2->execute();
|
||
|
||
$visitors = [];
|
||
while ($row = $result2->fetchArray(SQLITE3_ASSOC)) {
|
||
$visitors[] = $row;
|
||
}
|
||
|
||
echo json_encode(['success' => true, 'land' => $land, 'visitors' => $visitors]);
|
||
}
|
||
|
||
// ==================== 玩家端:添加访客 ====================
|
||
|
||
function handleAddVisitor($db, $playerName, $req) {
|
||
$landName = $req['name'] ?? $req['land'] ?? '';
|
||
$visitor = $req['visitor'] ?? $req['player'] ?? '';
|
||
|
||
if (empty($landName) || empty($visitor)) {
|
||
echo json_encode(['success' => false, 'error' => '缺少领地名或玩家名']);
|
||
return;
|
||
}
|
||
|
||
// ★ 校验玩家名格式(至少3字符,只含字母数字下划线)
|
||
if (!preg_match('/^[a-zA-Z0-9_]{3,16}$/', $visitor)) {
|
||
echo json_encode(['success' => false, 'error' => '无效的玩家名: ' . $visitor]);
|
||
return;
|
||
}
|
||
|
||
// ★ 校验玩家是否存在于数据库(login.db或web用户表)
|
||
if (!playerExists($db, $visitor)) {
|
||
echo json_encode(['success' => false, 'error' => '玩家不存在: ' . $visitor . ',请确认玩家已注册']);
|
||
return;
|
||
}
|
||
|
||
// 获取领地
|
||
$stmt = $db->prepare("SELECT * FROM web_area_lands WHERE name = :name");
|
||
$stmt->bindValue(':name', $landName, SQLITE3_TEXT);
|
||
$result = $stmt->execute();
|
||
$land = $result->fetchArray(SQLITE3_ASSOC);
|
||
|
||
if (!$land) {
|
||
echo json_encode(['success' => false, 'error' => '领地不存在']);
|
||
return;
|
||
}
|
||
|
||
if ($land['owner'] !== $playerName) {
|
||
echo json_encode(['success' => false, 'error' => '只有领地所有者才能添加访客']);
|
||
return;
|
||
}
|
||
|
||
// 插入访客
|
||
$stmt2 = $db->prepare("INSERT OR REPLACE INTO web_area_permissions
|
||
(land_id, land_name, player_name, role, permissions, granted_at, expires_at, synced_at)
|
||
VALUES (:land_id, :land_name, :player, 'visitor', '', :now, 0, :now)");
|
||
$stmt2->bindValue(':land_id', (int)$land['id'], SQLITE3_INTEGER);
|
||
$stmt2->bindValue(':land_name', $landName, SQLITE3_TEXT);
|
||
$stmt2->bindValue(':player', $visitor, SQLITE3_TEXT);
|
||
$stmt2->bindValue(':now', time(), SQLITE3_INTEGER);
|
||
$stmt2->execute();
|
||
|
||
echo json_encode(['success' => true, 'message' => "已添加访客: $visitor"]);
|
||
}
|
||
|
||
/**
|
||
* ★ 检查玩家是否存在于数据库
|
||
*/
|
||
function playerExists($db, $playerName) {
|
||
// 检查web用户表
|
||
try {
|
||
$stmt = $db->prepare("SELECT COUNT(*) as cnt FROM weblogin_tokens WHERE player = :player");
|
||
$stmt->bindValue(':player', $playerName, SQLITE3_TEXT);
|
||
$result = $stmt->execute();
|
||
$row = $result->fetchArray(SQLITE3_ASSOC);
|
||
if ($row && $row['cnt'] > 0) return true;
|
||
} catch (\Throwable $e) {
|
||
// 表可能不存在,忽略
|
||
}
|
||
|
||
// 检查users表
|
||
try {
|
||
$stmt = $db->prepare("SELECT COUNT(*) as cnt FROM users WHERE player_name = :player");
|
||
$stmt->bindValue(':player', $playerName, SQLITE3_TEXT);
|
||
$result = $stmt->execute();
|
||
$row = $result->fetchArray(SQLITE3_ASSOC);
|
||
if ($row && $row['cnt'] > 0) return true;
|
||
} catch (\Throwable $e) {
|
||
// 表可能不存在,忽略
|
||
}
|
||
|
||
// 检查tokens表
|
||
try {
|
||
$stmt = $db->prepare("SELECT COUNT(*) as cnt FROM tokens WHERE player = :player");
|
||
$stmt->bindValue(':player', $playerName, SQLITE3_TEXT);
|
||
$result = $stmt->execute();
|
||
$row = $result->fetchArray(SQLITE3_ASSOC);
|
||
if ($row && $row['cnt'] > 0) return true;
|
||
} catch (\Throwable $e) {
|
||
// 表可能不存在,忽略
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
// ==================== 玩家端:移除访客 ====================
|
||
|
||
function handleRemoveVisitor($db, $playerName, $req) {
|
||
$landName = $req['name'] ?? $req['land'] ?? '';
|
||
$visitor = $req['visitor'] ?? $req['player'] ?? '';
|
||
|
||
if (empty($landName) || empty($visitor)) {
|
||
echo json_encode(['success' => false, 'error' => '缺少领地名或玩家名']);
|
||
return;
|
||
}
|
||
|
||
// 获取领地
|
||
$stmt = $db->prepare("SELECT * FROM web_area_lands WHERE name = :name");
|
||
$stmt->bindValue(':name', $landName, SQLITE3_TEXT);
|
||
$result = $stmt->execute();
|
||
$land = $result->fetchArray(SQLITE3_ASSOC);
|
||
|
||
if (!$land) {
|
||
echo json_encode(['success' => false, 'error' => '领地不存在']);
|
||
return;
|
||
}
|
||
|
||
if ($land['owner'] !== $playerName) {
|
||
echo json_encode(['success' => false, 'error' => '只有领地所有者才能移除访客']);
|
||
return;
|
||
}
|
||
|
||
$stmt2 = $db->prepare("DELETE FROM web_area_permissions WHERE land_id = :land_id AND player_name = :player");
|
||
$stmt2->bindValue(':land_id', (int)$land['id'], SQLITE3_INTEGER);
|
||
$stmt2->bindValue(':player', $visitor, SQLITE3_TEXT);
|
||
$stmt2->execute();
|
||
|
||
echo json_encode(['success' => true, 'message' => "已移除访客: $visitor"]);
|
||
}
|
||
|
||
// ==================== 玩家端:访客列表 ====================
|
||
|
||
function handleListVisitors($db, $landName) {
|
||
if (empty($landName)) {
|
||
echo json_encode(['success' => false, 'error' => '缺少领地名称']);
|
||
return;
|
||
}
|
||
|
||
$stmt = $db->prepare("SELECT * FROM web_area_lands WHERE name = :name");
|
||
$stmt->bindValue(':name', $landName, SQLITE3_TEXT);
|
||
$result = $stmt->execute();
|
||
$land = $result->fetchArray(SQLITE3_ASSOC);
|
||
|
||
if (!$land) {
|
||
echo json_encode(['success' => false, 'error' => '领地不存在']);
|
||
return;
|
||
}
|
||
|
||
$stmt2 = $db->prepare("SELECT * FROM web_area_permissions WHERE land_id = :land_id ORDER BY granted_at DESC");
|
||
$stmt2->bindValue(':land_id', (int)$land['id'], SQLITE3_INTEGER);
|
||
$result2 = $stmt2->execute();
|
||
|
||
$visitors = [];
|
||
while ($row = $result2->fetchArray(SQLITE3_ASSOC)) {
|
||
$visitors[] = $row;
|
||
}
|
||
|
||
echo json_encode(['success' => true, 'visitors' => $visitors]);
|
||
}
|
||
|
||
// ==================== 玩家端:领地商店 ====================
|
||
|
||
function handleLandShop($db, $landName) {
|
||
$sql = "SELECT * FROM web_area_shop WHERE status = 'active'";
|
||
$params = [];
|
||
|
||
if (!empty($landName)) {
|
||
$sql .= " AND land_name = :name";
|
||
$params[':name'] = $landName;
|
||
}
|
||
$sql .= " ORDER BY created_at DESC LIMIT 50";
|
||
|
||
$stmt = $db->prepare($sql);
|
||
foreach ($params as $k => $v) {
|
||
$stmt->bindValue($k, $v, SQLITE3_TEXT);
|
||
}
|
||
$result = $stmt->execute();
|
||
|
||
$items = [];
|
||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||
$items[] = $row;
|
||
}
|
||
|
||
echo json_encode(['success' => true, 'items' => $items]);
|
||
}
|
||
|
||
// ==================== 玩家端:获取访客权限 ====================
|
||
|
||
function handleGetVisitorPerm($db, $playerName, $landName) {
|
||
if (empty($landName)) {
|
||
echo json_encode(['success' => false, 'error' => '缺少领地名称']);
|
||
return;
|
||
}
|
||
|
||
$stmt = $db->prepare("SELECT * FROM web_area_lands WHERE name = :name");
|
||
$stmt->bindValue(':name', $landName, SQLITE3_TEXT);
|
||
$result = $stmt->execute();
|
||
$land = $result->fetchArray(SQLITE3_ASSOC);
|
||
|
||
if (!$land) {
|
||
echo json_encode(['success' => false, 'error' => '领地不存在']);
|
||
return;
|
||
}
|
||
|
||
// 获取该玩家的权限
|
||
$stmt2 = $db->prepare("SELECT * FROM web_area_permissions WHERE land_id = :land_id AND player_name = :player");
|
||
$stmt2->bindValue(':land_id', (int)$land['id'], SQLITE3_INTEGER);
|
||
$stmt2->bindValue(':player', $playerName, SQLITE3_TEXT);
|
||
$result2 = $stmt2->execute();
|
||
$perm = $result2->fetchArray(SQLITE3_ASSOC);
|
||
|
||
echo json_encode(['success' => true, 'permission' => $perm]);
|
||
}
|
||
|
||
// ==================== 玩家端:更新访客权限 ====================
|
||
|
||
function handleUpdateVisitorPerm($db, $playerName, $post) {
|
||
$landName = $post['land'] ?? '';
|
||
$visitor = $post['visitor'] ?? '';
|
||
$permissions = $post['permissions'] ?? '';
|
||
$role = $post['role'] ?? 'visitor';
|
||
|
||
if (empty($landName) || empty($visitor)) {
|
||
echo json_encode(['success' => false, 'error' => '缺少领地名或玩家名']);
|
||
return;
|
||
}
|
||
|
||
// 获取领地
|
||
$stmt = $db->prepare("SELECT * FROM web_area_lands WHERE name = :name");
|
||
$stmt->bindValue(':name', $landName, SQLITE3_TEXT);
|
||
$result = $stmt->execute();
|
||
$land = $result->fetchArray(SQLITE3_ASSOC);
|
||
|
||
if (!$land) {
|
||
echo json_encode(['success' => false, 'error' => '领地不存在']);
|
||
return;
|
||
}
|
||
|
||
// 权限检查:只有所有者能更新权限
|
||
if ($land['owner'] !== $playerName) {
|
||
echo json_encode(['success' => false, 'error' => '只有领地所有者才能更新权限']);
|
||
return;
|
||
}
|
||
|
||
// 更新权限
|
||
$stmt2 = $db->prepare("INSERT OR REPLACE INTO web_area_permissions
|
||
(land_id, land_name, player_name, role, permissions, granted_at, expires_at, synced_at)
|
||
VALUES (:land_id, :land_name, :player, :role, :perms, :now, 0, :now)");
|
||
$stmt2->bindValue(':land_id', (int)$land['id'], SQLITE3_INTEGER);
|
||
$stmt2->bindValue(':land_name', $landName, SQLITE3_TEXT);
|
||
$stmt2->bindValue(':player', $visitor, SQLITE3_TEXT);
|
||
$stmt2->bindValue(':role', $role, SQLITE3_TEXT);
|
||
$stmt2->bindValue(':perms', $permissions, SQLITE3_TEXT);
|
||
$stmt2->bindValue(':now', time(), SQLITE3_INTEGER);
|
||
$stmt2->execute();
|
||
|
||
// ★ 写入web_admin_changes以便Java同步
|
||
$stmt4 = $db->prepare("INSERT INTO web_admin_changes (change_type, target_id, target_name, change_data, created_at) VALUES ('perm_change', :id, :name, :data, :now)");
|
||
$stmt4->bindValue(':id', (int)$land['id'], SQLITE3_INTEGER);
|
||
$stmt4->bindValue(':name', $visitor, SQLITE3_TEXT);
|
||
$stmt4->bindValue(':data', json_encode(['land_name' => $landName, 'permissions' => $permissions, 'role' => $role]), SQLITE3_TEXT);
|
||
$stmt4->bindValue(':now', time(), SQLITE3_INTEGER);
|
||
$stmt4->execute();
|
||
|
||
echo json_encode(['success' => true, 'message' => "已更新 $visitor 的权限"]);
|
||
}
|
||
|
||
// ==================== 成员独立权限操作 ====================
|
||
|
||
/**
|
||
* 29种权限类型定义
|
||
*/
|
||
$PERM_TYPES = [
|
||
'denyMove' => '移动',
|
||
'denyBlockPlace' => '放置方块',
|
||
'denyBlockBreak' => '破坏方块',
|
||
'denyPVP' => 'PVP战斗',
|
||
'denyMount' => '骑乘',
|
||
'denyEnderPearl' => '末影珍珠',
|
||
'denyThrownProjectiles' => '投掷物',
|
||
'denyRaid' => '袭击',
|
||
'denyBow' => '弓箭',
|
||
'denyPotion' => '药水',
|
||
'denyFire' => '点火',
|
||
'denyFireSpread' => '火焰蔓延',
|
||
'denyPickup' => '拾取物品',
|
||
'denyDrop' => '丢弃物品',
|
||
'denyExplosion' => '爆炸',
|
||
'denyFallDamage' => '摔落伤害',
|
||
'denyHunger' => '饥饿',
|
||
'denyAllDamage' => '所有伤害',
|
||
'denyAllEffects' => '所有效果',
|
||
'denyItemFrame' => '物品展示框',
|
||
'denyRedstoneInteraction' => '红石交互',
|
||
'denyDoorInteraction' => '门禁交互',
|
||
'denyNoteblockJukebox' => '音符盒/唱片机',
|
||
'denyLead' => '拴绳',
|
||
'denyCropHarvest' => '收割作物',
|
||
'denyWoolShear' => '剪羊毛',
|
||
'denyAnimalFeeding' => '投喂动物',
|
||
'denyGlowing' => '发光效果',
|
||
'denyPeaceMode' => '和平模式'
|
||
];
|
||
|
||
function handleGetMemberPerms($db, $playerName, $landName) {
|
||
global $PERM_TYPES;
|
||
|
||
if (empty($landName)) {
|
||
echo json_encode(['success' => false, 'error' => '缺少领地名称']);
|
||
return;
|
||
}
|
||
|
||
// 获取领地
|
||
$stmt = $db->prepare("SELECT * FROM web_area_lands WHERE name = :name");
|
||
$stmt->bindValue(':name', $landName, SQLITE3_TEXT);
|
||
$result = $stmt->execute();
|
||
$land = $result->fetchArray(SQLITE3_ASSOC);
|
||
|
||
if (!$land) {
|
||
echo json_encode(['success' => false, 'error' => '领地不存在']);
|
||
return;
|
||
}
|
||
|
||
// 权限检查:只有所有者能编辑成员权限
|
||
if ($land['owner'] !== $playerName) {
|
||
echo json_encode(['success' => false, 'error' => '只有领地所有者才能编辑成员权限']);
|
||
return;
|
||
}
|
||
|
||
// 获取所有成员及其权限
|
||
$stmt2 = $db->prepare("SELECT * FROM web_area_permissions WHERE land_id = :land_id ORDER BY player_name");
|
||
$stmt2->bindValue(':land_id', (int)$land['id'], SQLITE3_INTEGER);
|
||
$result2 = $stmt2->execute();
|
||
|
||
$members = [];
|
||
while ($row = $result2->fetchArray(SQLITE3_ASSOC)) {
|
||
// 解析权限JSON
|
||
$permJson = $row['permissions'] ?? '';
|
||
$perms = [];
|
||
if (!empty($permJson)) {
|
||
$decoded = json_decode($permJson, true);
|
||
if (is_array($decoded)) {
|
||
$perms = $decoded;
|
||
}
|
||
}
|
||
$row['perm_map'] = $perms;
|
||
$members[] = $row;
|
||
}
|
||
|
||
echo json_encode([
|
||
'success' => true,
|
||
'land' => $land,
|
||
'members' => $members,
|
||
'perm_types' => $PERM_TYPES
|
||
]);
|
||
}
|
||
|
||
function handleUpdateMemberPerm($db, $playerName, $post) {
|
||
$landName = $post['land'] ?? '';
|
||
$targetPlayer = $post['player'] ?? '';
|
||
$permKey = $post['perm'] ?? '';
|
||
$enabled = isset($post['enabled']) ? (bool)$post['enabled'] : false;
|
||
|
||
if (empty($landName) || empty($targetPlayer) || empty($permKey)) {
|
||
echo json_encode(['success' => false, 'error' => '缺少参数']);
|
||
return;
|
||
}
|
||
|
||
// 获取领地
|
||
$stmt = $db->prepare("SELECT * FROM web_area_lands WHERE name = :name");
|
||
$stmt->bindValue(':name', $landName, SQLITE3_TEXT);
|
||
$result = $stmt->execute();
|
||
$land = $result->fetchArray(SQLITE3_ASSOC);
|
||
|
||
if (!$land) {
|
||
echo json_encode(['success' => false, 'error' => '领地不存在']);
|
||
return;
|
||
}
|
||
|
||
// 权限检查
|
||
if ($land['owner'] !== $playerName) {
|
||
echo json_encode(['success' => false, 'error' => '只有领地所有者才能编辑成员权限']);
|
||
return;
|
||
}
|
||
|
||
// 获取当前权限
|
||
$stmt2 = $db->prepare("SELECT * FROM web_area_permissions WHERE land_id = :land_id AND player_name = :player");
|
||
$stmt2->bindValue(':land_id', (int)$land['id'], SQLITE3_INTEGER);
|
||
$stmt2->bindValue(':player', $targetPlayer, SQLITE3_TEXT);
|
||
$result2 = $stmt2->execute();
|
||
$perm = $result2->fetchArray(SQLITE3_ASSOC);
|
||
|
||
if (!$perm) {
|
||
echo json_encode(['success' => false, 'error' => '该玩家不是领地成员']);
|
||
return;
|
||
}
|
||
|
||
// 解析现有权限
|
||
$permMap = [];
|
||
$permJson = $perm['permissions'] ?? '';
|
||
if (!empty($permJson)) {
|
||
$decoded = json_decode($permJson, true);
|
||
if (is_array($decoded)) {
|
||
$permMap = $decoded;
|
||
}
|
||
}
|
||
|
||
// 更新权限
|
||
if ($enabled) {
|
||
$permMap[$permKey] = true;
|
||
} else {
|
||
unset($permMap[$permKey]);
|
||
}
|
||
|
||
// 写回数据库
|
||
$newJson = json_encode($permMap, JSON_UNESCAPED_UNICODE);
|
||
$stmt3 = $db->prepare("UPDATE web_area_permissions SET permissions = :perms, synced_at = :now WHERE land_id = :land_id AND player_name = :player");
|
||
$stmt3->bindValue(':perms', $newJson, SQLITE3_TEXT);
|
||
$stmt3->bindValue(':now', time(), SQLITE3_INTEGER);
|
||
$stmt3->bindValue(':land_id', (int)$land['id'], SQLITE3_INTEGER);
|
||
$stmt3->bindValue(':player', $targetPlayer, SQLITE3_TEXT);
|
||
$stmt3->execute();
|
||
|
||
echo json_encode(['success' => true, 'message' => "已更新 $targetPlayer 的 $permKey 权限"]);
|
||
}
|
||
|
||
function handleClearMemberPerm($db, $playerName, $post) {
|
||
$landName = $post['land'] ?? '';
|
||
$targetPlayer = $post['player'] ?? '';
|
||
|
||
if (empty($landName) || empty($targetPlayer)) {
|
||
echo json_encode(['success' => false, 'error' => '缺少参数']);
|
||
return;
|
||
}
|
||
|
||
// 获取领地
|
||
$stmt = $db->prepare("SELECT * FROM web_area_lands WHERE name = :name");
|
||
$stmt->bindValue(':name', $landName, SQLITE3_TEXT);
|
||
$result = $stmt->execute();
|
||
$land = $result->fetchArray(SQLITE3_ASSOC);
|
||
|
||
if (!$land) {
|
||
echo json_encode(['success' => false, 'error' => '领地不存在']);
|
||
return;
|
||
}
|
||
|
||
// 权限检查
|
||
if ($land['owner'] !== $playerName) {
|
||
echo json_encode(['success' => false, 'error' => '只有领地所有者才能清除成员权限']);
|
||
return;
|
||
}
|
||
|
||
// 获取旧权限
|
||
$stmt_old = $db->prepare("SELECT permissions FROM web_area_permissions WHERE land_id = :land_id AND player_name = :player");
|
||
$stmt_old->bindValue(':land_id', (int)$land['id'], SQLITE3_INTEGER);
|
||
$stmt_old->bindValue(':player', $targetPlayer, SQLITE3_TEXT);
|
||
$result_old = $stmt_old->execute();
|
||
$old_perm = $result_old->fetchArray(SQLITE3_ASSOC);
|
||
$old_perms = $old_perm ? ($old_perm['permissions'] ?? '') : '';
|
||
|
||
// 清除权限
|
||
$stmt2 = $db->prepare("UPDATE web_area_permissions SET permissions = '', synced_at = :now WHERE land_id = :land_id AND player_name = :player");
|
||
$stmt2->bindValue(':now', time(), SQLITE3_INTEGER);
|
||
$stmt2->bindValue(':land_id', (int)$land['id'], SQLITE3_INTEGER);
|
||
$stmt2->bindValue(':player', $targetPlayer, SQLITE3_TEXT);
|
||
$stmt2->execute();
|
||
|
||
// 记录变更
|
||
if (!empty($old_perms)) {
|
||
$stmt3 = $db->prepare("INSERT INTO web_admin_changes (change_type, target_id, target_name, change_data, created_at) VALUES ('perm_clear', :id, :name, :data, :now)");
|
||
$stmt3->bindValue(':id', (int)$land['id'], SQLITE3_INTEGER);
|
||
$stmt3->bindValue(':name', $targetPlayer, SQLITE3_TEXT);
|
||
$stmt3->bindValue(':data', json_encode(['land_name' => $landName, 'old_permissions' => $old_perms]), SQLITE3_TEXT);
|
||
$stmt3->bindValue(':now', time(), SQLITE3_INTEGER);
|
||
$stmt3->execute();
|
||
}
|
||
|
||
echo json_encode(['success' => true, 'message' => "已清除 $targetPlayer 的所有自定义权限"]);
|
||
}
|
||
|
||
// ==================== Java端轮询PHP管理员变更 ====================
|
||
|
||
function handlePollAdminChanges($db, $get) {
|
||
$lastId = (int)($get['last_id'] ?? 0);
|
||
$limit = min((int)($get['limit'] ?? 50), 100);
|
||
|
||
// 获取未确认的变更
|
||
$stmt = $db->prepare("SELECT * FROM web_admin_changes WHERE id > :last_id AND acknowledged = 0 ORDER BY id ASC LIMIT :limit");
|
||
$stmt->bindValue(':last_id', $lastId, SQLITE3_INTEGER);
|
||
$stmt->bindValue(':limit', $limit, SQLITE3_INTEGER);
|
||
$result = $stmt->execute();
|
||
|
||
$changes = [];
|
||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||
$changes[] = $row;
|
||
}
|
||
|
||
echo json_encode(['success' => true, 'changes' => $changes, 'count' => count($changes)], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||
}
|
||
|
||
function handleAckAdminChanges($db, $post) {
|
||
$ids = $post['ids'] ?? ($_GET['ids'] ?? '');
|
||
if (empty($ids)) {
|
||
echo json_encode(['success' => false, 'error' => 'missing ids']);
|
||
return;
|
||
}
|
||
|
||
$idList = array_filter(array_map('intval', explode(',', $ids)));
|
||
if (empty($idList)) {
|
||
echo json_encode(['success' => false, 'error' => 'invalid ids']);
|
||
return;
|
||
}
|
||
|
||
$now = time();
|
||
$placeholders = implode(',', array_fill(0, count($idList), '?'));
|
||
$stmt = $db->prepare("UPDATE web_admin_changes SET acknowledged = 1, acked_at = :now WHERE id IN ($placeholders)");
|
||
$stmt->bindValue(':now', $now, SQLITE3_INTEGER);
|
||
$i = 1;
|
||
foreach ($idList as $id) {
|
||
$stmt->bindValue($i++, $id, SQLITE3_INTEGER);
|
||
}
|
||
$stmt->execute();
|
||
|
||
echo json_encode(['success' => true, 'acked' => count($idList)]);
|
||
}
|
||
|
||
function validateSecret($secret) {
|
||
if (empty($secret)) return false;
|
||
$validSecrets = [
|
||
'sdf1_web_comm_2026_ypshidifu'
|
||
];
|
||
return in_array($secret, $validSecrets);
|
||
}
|