Yii2 のルールは、モデルの属性を検証するために使用されます。シナリオ ユーザーは、さまざまなシナリオで検証する必要があるモデルを定義します。以下の記事では、Yii2 のシナリオ (シナリオ) と検証ルール (ルール) に関する関連情報を主に紹介します。この記事ではサンプルコードを通して詳しく紹介していますので、困っている友人は参考にしてください。
序文
シーンとは、その名の通り、状況、場面のことです。 yii2 にも、あなたが理解しているシーンと同様の意味を持つシーンがあります。
ユーザーと対話するシステムの重要な機能には、ユーザー データの収集、検証、処理が含まれます。実際のビジネスでは、データを永続的に保存する必要があることがよくあります。セキュリティ上の理由から、開発者は「クライアントからの入力は信頼できない」という原則をしっかりと理解し、クライアントから送信されたデータは、内部システムに保存または転送される前にフィルタリングおよびクリーニングされる必要があります。
Yii2 では、ユーザー データの収集と検証に Model クラスを使用することを推奨しており、永続的な ActiveRecord クラスはそのサブクラスです。 Model クラスのロード メソッドと検証メソッドは、それぞれクライアント データの収集と検証に使用されます。どのデータを収集し、どのシナリオでどのデータを検証する必要があるかが、この記事のテーマです。シナリオと検証ルールです。
以下では多くを語る必要はありません。編集者に従って詳細な紹介を見てみましょう。
#システム構造
生徒登録
public function actionSignup() { $data = Yii::$app->request->post(); $user = new User(); $user->load($data); if ($user->save()) { $student = new Student([ "user_id" => $user->id, ]); $student->load($data); if ($student->save()) { // redirect to success page } else { $user->delete(); } } // render error page }
namespace app\models; class User extends \yii\db\ActiveRecord { public function rules() { return [ [["username", "password", "status",], "required"], ["username", "unique"], // other rules ]; } // other method }
情報の変更
1. ユーザー パスワードの検証
登録時にユーザー パスワードが検証されます。ユーザーのパスワードが 8 ~ 16 桁であるかどうかに関係なく、パスワード ルールは["password", "string", "length" => [8, 16]] になります。パスワードを平文で保存することはお勧めできません。データベースに挿入する際には、少なくとも MD5 暗号化が実行され、パスワードは 32 ビットになります。ユーザーが情報を変更する際にパスワードを変更しなかったと仮定し、再度保存すると、パスワード規則の検証エラー(長さが一致しない)が発生し、保存できません。
public function rules() { return [ ["password", "string", "length" => [8, 16], 'when' => function ($model) { return $model->isNewRecord; }], // other rules ];
2. ユーザーが個人的にパスワードを変更できないようにする
システムが Yii フレームワークを使用して作られていることを発見した賢い人 (トムなど) がいると仮定します。ダメージを与えたいのでスキルを見せつけてください。情報を変更するためにフォームを送信するときに、トムは &password=12345678 を追加します。システムは、$user->load($data) を使用してユーザー入力を収集し、パスワード フィールドを更新します。これにより、次の結果が生じます: ルール設定の更新時にパスワード フィールドが検証されず、12345678はパスワード値としてデータベースに直接保存されます。この操作により連鎖反応が発生しました。ユーザーが再度ログインすると、暗号化されたパスワードがデータベース内の平文パスワードと一致せず、トムはシステムにログインできなくなりました。厄介なのは、トムが厄介者で、ログインできなくなった後は一日中カスタマー サービスに嫌がらせをするので、心配するのは簡単ではありません。
unset($data["password"]); $user->load($data); // 或者 $password = $user->password; $user->load($data); $user->password = $password;
可以按照密码的方法,逐个屏蔽受保护属性,但显得啰嗦难看(虽然好使)。如果受保护属性多,可以仅允许白名单进入,具体操作为:新增一个UpdateInfoForm类继承Model,属性是白名单属性合计。用UpdateInfoForm类过滤用户数据,校验通过后再更新到user和student中:
$form = new UpdateInfoForm(); $form->load($data); if ($form->validate()) { $user->load($form->attributes); $student->load($form->attributes); // next biz }
这种方式更优雅,但仔细一想代价不小:属性和验证规则要重复写一遍;user和student保存时又重复校验属性。这种方式看起来优雅,实际上却冗余又低效。
scenario的登场,完美的解决解决上述问题。
场景(scenario)
分析上面问题,会发现关键点是批量赋值(massive assignment)和数据校验(validate)两个方法。如果对不同的场景指定赋值字段和检验规则,问题就迎刃而解。
Yii中的scenario有 安全属性 和 活跃属性 两个概念。安全属性用在批量赋值的load方法,只有安全属性才能被赋值;活跃属性用在规则校验的validate方法,在活跃属性集中并且定义了校验规则的属性才会被校验。活跃属性和安全属性的关系是,安全属性是活跃属性的子集。
\yii\base\Model类定义了默认场景:SCENARIO_DEFAULT(值为default)。默认场景下,出现在rules方法中的属性既是活跃属性,又是安全属性(这句话基本正确,看后续解释)。为不同场景指定活跃属性、安全属性以及校验器,可以通过覆盖senarios或rules两个方法实现(几乎每个Model类都会重写rules方法,senarios用得少)。
rules
先看rules方法。默认的属性加校验器定义方式,让每个属性既是安全属性,也是活跃属性。如果想让某个属性不是安全属性(不能通过load批量赋值),在属性名前加感叹号!即可。例如student中的user_id字段:
public function rules() { return [ ["!user_od", "required"], ["!user_id", "integer"], ["!user_od", "unique"], // other rules ]; }
user_id是活跃属性,在写入数据库时会被校验。但它不是安全属性,不能通过load方法进行赋值,解决了安全隐患。
再看rules方法按场景区分校验器规则的做法:定义校验器时on属性指定规则在哪些场景下生效,except属性则排除一些场景(如果不指定on和except,规则对所有场景生效)。例如:
public function rules() { return [ ["password", "string", "length" => [8, 16], "on" => ["signup"]], // 仅在signup场景时才被验证 ["status", "integer", "except" => ["signup"], // 除了signup场景,其他情况都校验 // other rules ]; }
在原来基础上新增感叹号和on/except属性,非常简便的就定义了非安全属性以及分场景指定校验规则。
scenarios
另外一种更清晰定义安全属性和活跃属性的做法是重写scenarios方法。scenarios方法返回一个数组,数组的键是场景名称,值是活跃属性集合(包饭安全属性)。例如student表的可能实现如下:
public function scenarios() { return [ self::SCENARIO_DEFAULT => ["!user_id", "grade", "class", xxxx], "update" => ["grade", "class", xxxx], ]; }
默认情形下(学生报名),年级、班级这些信息是安全属性,但user_id不是,只能在程序内部赋值,并在插入数据时被校验;在修改信息时,user_id不是活跃属性,既不能被批量赋值,也不需要校验(事实上它不应该改变)。
scenarios方法只能定义活跃属性和安全属性,无法定义校验规则,需要和rules配合使用。
总结
金肯定义完善的数据校验规则
业务复杂时定义多个场景,仔细为每个场景定义安全属性和校验规则
优先使用rules;属性较多、rules复杂时,可以配合scenarios方法迅速理清安全属性和活跃属性
参考
http://www.yiiframework.com/doc-2.0/guide-input-validation.html
MixPHP、Yii和CodeIgniter的并发压力测试的小结
PHP基于非递归算法实现先序、中序及后序遍历二叉树操作的示例
以上がYii2のシナリオと検証ルールの詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。