yii2 不自动校验或转换 post 参数,必须显式校验:先用 $request->post('id', null) 取原始值,再用 filter_var 校验;模型中定义 rules() 进行结构化校验;json 请求需 getrawbody() 解析后校验,并携带 csrf token。

Yii2 不会自动校验 POST 请求参数,更不会自动转换类型或过滤内容。所有校验必须显式定义和触发,否则传入的字符串、空值、非法数字都会原样进入业务逻辑,极易引发安全或数据异常问题。
先取原始值,再做校验
别用 (int)$_POST['id'] 或 $request->post('id') 直接转类型——这会把 'abc' 变成 0,把空字符串变成 0,完全丢失语义。正确做法是:
- 用
$request->getBody()(JSON)或$request->post()(表单)拿到原始数据数组 - 对每个关键字段单独提取:比如
$id = $request->post('id', null) - 立即用
filter_var($id, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]])校验是否为合法正整数 - 校验失败就抛出
BadRequestHttpException,不往下走
用模型规则做结构化校验
适合字段多、需统一处理、要返回标准错误格式的场景。在模型中定义 rules():
- 基础类型校验:
['age', 'integer', 'min' => 1, 'max' => 120] - 枚举值限制:
['status', 'in', 'range' => ['draft', 'published']] - 存在性检查:
['user_id', 'exist', 'targetClass' => User::class, 'targetAttribute' => 'id'] - 空值控制:加
'skipOnEmpty' => false确保即使字段为空也执行该条规则
控制器里调用 $model->load(Yii::$app->request->post(), '')(注意第二个参数为空字符串,避免默认前缀),再 $model->validate() 即可。
复杂逻辑用自定义验证器
当内置规则不够用,比如要校验手机号格式+运营商+归属地,或校验两个字段是否一致,就得自己写:
-
内联验证器:适合简单逻辑,直接写在
rules()里,用匿名函数,签名必须是function ($model, $attribute, $params),失败时调$model->addError($attribute, $msg) -
独立验证类:新建
PhoneValidator extends Validator,重写validateAttribute(),类名必须以Validator结尾,参数通过 public 属性声明(如public $strict = true),并在 rules 中传入
特别注意 JSON POST 请求
前端发 Content-Type: application/json 时,$_POST 是空的,$request->post() 也拿不到数据。必须:
- 先用
$rawBody = $request->getRawBody()获取原始 JSON 字符串 - 再
$data = json_decode($rawBody, true)解析成数组 - 然后对
$data手动校验或赋值给模型($model->load($data, '')) - 别忘了 CSRF:JSON 请求需在 headers 中带上
X-CSRF-Token,服务端默认仍会校验










