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

PHP中如何基于预定义JSON表单结构校验提交的JSON数据合法性

PHP实现动态表单details字段非法字段拦截方案

你原来写的校验逻辑存在逻辑错误:双层遍历的判断规则会导致合法字段只要和其他任意表单项key不匹配就被误判为非法,完全无法正常工作。
正确实现的核心思路是提前提取表单配置里的所有合法key作为白名单,所有提交的字段只需要和白名单做比对即可,不需要双层循环遍历配置。同时可以附加格式、类型校验,避免非法结构写入JSON字段。


完整实现代码

/**
 * 校验employee表details提交数据合法性
 * @param array $data 前端提交的details数组(json_decode后的数组格式)
 * @param array $formDefinition 后台预定义的表单结构配置
 * @return bool 校验通过返回true
 * @throws InvalidArgumentException 校验不通过抛出对应错误
 */
public function dataValidator(array $data, array $formDefinition): bool
{
    // 预提取合法字段白名单、字段-类型映射表,只需要遍历一次表单配置
    $allowedKeys = array_column($formDefinition, 'key');
    $keyTypeMap = array_column($formDefinition, 'datatype', 'key');

    foreach ($data as $index => $item) {
        // 先校验基础结构:每个元素必须是单键值对结构,和约定的存储格式一致
        if (!is_array($item)) {
            throw new InvalidArgumentException(sprintf('第%d个数据项格式非法,必须为键值对对象', $index + 1));
        }
        if (count($item) !== 1) {
            throw new InvalidArgumentException(sprintf('第%d个数据项仅允许传入1个表单字段', $index + 1));
        }

        $currentKey = array_key_first($item);
        $currentValue = $item[$currentKey];

        // 核心白名单校验:不在预定义key列表里的字段直接拦截
        if (!in_array($currentKey, $allowedKeys, true)) {
            throw new InvalidArgumentException(sprintf('检测到未定义的非法字段:%s,禁止写入', $currentKey));
        }

        // 可选附加:按表单定义的datatype校验值类型,不需要可以删掉这段
        $expectedType = $keyTypeMap[$currentKey];
        $isTypeMatch = match ($expectedType) {
            'string' => is_string($currentValue),
            'boolean' => is_bool($currentValue),
            'choice' => is_scalar($currentValue), // 选项值一般是字符串/数字,可根据自身业务调整校验规则
            default => true
        };
        if (!$isTypeMatch) {
            throw new InvalidArgumentException(sprintf('字段%s类型错误,期望类型为%s', $currentKey, $expectedType));
        }
    }

    return true;
}

调用示例

// 你的预定义表单配置(注意原配置里isRetired的value为空属于语法错误,这里补为null)
$formDefinition = [
    ['key' => 'name', 'value' => '', 'datatype' => 'string'],
    ['key' => 'sex', 'value' => '', 'datatype' => 'choice'],
    ['key' => 'occupation', 'value' => '', 'datatype' => 'string'],
    ['key' => 'isRetired', 'value' => null, 'datatype' => 'boolean']
];

// 前端提交后,先把JSON字符串转成数组再传入校验
$submitDetails = json_decode($request->input('details'), true);

try {
    $this->dataValidator($submitDetails, $formDefinition);
    // 校验通过再写入数据库
    $employee = Employee::find($id);
    $employee->details = json_encode($submitDetails);
    $employee->save();
} catch (InvalidArgumentException $e) {
    // 校验失败直接返回错误提示
    return back()->with('error', $e->getMessage());
}

校验效果说明

  • 所有未在formDefinition中定义的字段(比如额外传入age、address等字段)会被直接拦截,从根源杜绝非法字段写入
  • 不符合约定存储结构的数据(比如单个数组元素塞多个键值对、传入非键值对格式内容)会被提前拦截
  • 附加的类型校验可以过滤和字段预期类型不匹配的内容,减少后续数据读取、展示时的异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 05:48:28