You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WHMCS限制特定产品/客户组的钩子失效问题排查

你的WHMCS钩子代码存在的问题及修复方案

1. 钩子注册方式错误:嵌套钩子无法正常生效

你把AdminProductsServices和AdminClientsSearch钩子嵌套在了AdminAreaHeadOutput钩子内部。WHMCS的钩子注册是全局生效的,这种嵌套方式会导致:

  • 每次AdminAreaHeadOutput触发(几乎每个管理员页面加载时)都会重复注册内部钩子,引发逻辑混乱
  • 内部钩子的注册时机晚于实际需要执行的时机,导致过滤逻辑根本没被触发

正确的做法是直接全局注册所有钩子,不要嵌套。

2. 产品/服务过滤逻辑完全错误

你当前的代码查询的是tblproducts(产品模板表)的ID,但AdminProductsServices钩子的$vars['products']实际是客户的服务数据(来自tblhosting表),服务的id和产品模板的id不是同一个概念。而且你需要关联服务对应的产品模板所属的分组,而不是直接过滤产品模板ID。

另外,你只处理了产品服务页面的展示,但管理员可能通过其他入口访问到未授权服务,还需要覆盖更多相关钩子。

3. 客户过滤范围不全

AdminClientsSearch钩子仅处理搜索结果的过滤,但管理员直接访问客户列表页面时,这个钩子不会触发,导致未授权客户依然能被看到。你需要添加AdminClientsList钩子来处理客户列表的过滤,同时还要限制单个客户详情页面的访问。

4. 变量获取与修改的问题

  • 直接读取$_SESSION['adminid']不安全,WHMCS钩子的$vars参数已经包含adminid,可以直接用$vars['adminid']
  • 修改$vars数组时,unset元素后数组会留下空键,可能导致页面渲染异常,建议过滤后重新生成数组而不是直接删除元素

修复后的示例代码

<?php
use WHMCS\Database\Capsule;

// 定义权限配置
$restrictedAdminId = 3;
$allowedProductGroupId = 2;
$allowedClientGroupId = 1;

// 检查当前管理员是否是受限用户
function isRestrictedAdmin() {
    global $restrictedAdminId;
    return isset($_SESSION['adminid']) && $_SESSION['adminid'] == $restrictedAdminId;
}

// 过滤产品服务列表
add_hook('AdminServicesList', 1, function($vars) use ($allowedProductGroupId) {
    if (!isRestrictedAdmin()) return $vars;

    // 获取允许的产品模板ID
    $allowedProductIds = Capsule::table('tblproducts')
        ->where('gid', $allowedProductGroupId)
        ->pluck('id')
        ->toArray();

    // 过滤服务:只保留属于允许产品模板的服务
    $filteredServices = array_filter($vars['services'], function($service) use ($allowedProductIds) {
        return in_array($service['pid'], $allowedProductIds);
    });

    $vars['services'] = array_values($filteredServices);
    return $vars;
});

// 过滤客户列表
add_hook('AdminClientsList', 1, function($vars) use ($allowedClientGroupId) {
    if (!isRestrictedAdmin()) return $vars;

    // 获取允许的客户ID
    $allowedClientIds = Capsule::table('tblclients')
        ->where('groupid', $allowedClientGroupId)
        ->pluck('id')
        ->toArray();

    // 过滤客户列表
    $filteredClients = array_filter($vars['clients'], function($client) use ($allowedClientIds) {
        return in_array($client['id'], $allowedClientIds);
    });

    $vars['clients'] = array_values($filteredClients);
    return $vars;
});

// 过滤客户搜索结果
add_hook('AdminClientsSearch', 1, function($vars) use ($allowedClientGroupId) {
    if (!isRestrictedAdmin()) return $vars;

    $allowedClientIds = Capsule::table('tblclients')
        ->where('groupid', $allowedClientGroupId)
        ->pluck('id')
        ->toArray();

    $filteredResults = array_filter($vars['results'], function($result) use ($allowedClientIds) {
        return in_array($result['id'], $allowedClientIds);
    });

    $vars['results'] = array_values($filteredResults);
    return $vars;
});

// 限制访问未授权客户详情页面
add_hook('AdminClientEdit', 1, function($vars) use ($allowedClientGroupId) {
    if (!isRestrictedAdmin()) return $vars;

    $client = Capsule::table('tblclients')->find($vars['userid']);
    if (!$client || $client->groupid != $allowedClientGroupId) {
        header("Location: index.php?module=clients");
        exit;
    }
    return $vars;
});

内容的提问来源于stack exchange,提问作者whoo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 22:23:21