ホームページ > バックエンド開発 > PHPチュートリアル > Yii2のシナリオと検証ルールの詳細説明

Yii2のシナリオと検証ルールの詳細説明

jacklove
リリース: 2023-04-02 08:06:01
オリジナル
3916 人が閲覧しました

Yii2 のルールは、モデルの属性を検証するために使用されます。シナリオ ユーザーは、さまざまなシナリオで検証する必要があるモデルを定義します。以下の記事では、Yii2 のシナリオ (シナリオ) と検証ルール (ルール) に関する関連情報を主に紹介します。この記事ではサンプルコードを通して詳しく紹介していますので、困っている友人は参考にしてください。

序文

シーンとは、その名の通り、状況、場面のことです。 yii2 にも、あなたが理解しているシーンと同様の意味を持つシーンがあります。

ユーザーと対話するシステムの重要な機能には、ユーザー データの収集、検証、処理が含まれます。実際のビジネスでは、データを永続的に保存する必要があることがよくあります。セキュリティ上の理由から、開発者は「クライアントからの入力は信頼できない」という原則をしっかりと理解し、クライアントから送信されたデータは、内部システムに保存または転送される前にフィルタリングおよびクリーニングされる必要があります。

Yii2 では、ユーザー データの収集と検証に Model クラスを使用することを推奨しており、永続的な ActiveRecord クラスはそのサブクラスです。 Model クラスのロード メソッドと検証メソッドは、それぞれクライアント データの収集と検証に使用されます。どのデータを収集し、どのシナリオでどのデータを検証する必要があるかが、この記事のテーマです。シナリオと検証ルールです。

以下では多くを語る必要はありません。編集者に従って詳細な紹介を見てみましょう。

#システム構造

#最初に簡単なビジネス システムを紹介します。システム内には生徒と教師の 2 つの役割があり、使用されます。データベース内にロール情報を保存するために 3 つのテーブルが作成されます:

user: [id、username、password、status、その他の共通属性]

student: [id、user_id、student_no、grade、クラス、他の生徒の属性]

Teacher: [id、user_id、work_no、役職、電話番号、その他の教師の属性]

実際の業務は追加、削除、クエリ、変更に限定されません。これら 3 つのテーブルの操作を説明します。問題を単純化するために、ユーザー テーブルと学生テーブルのデータ変更についてのみ後で説明します (教師テーブルは、データベースを設計した人が愚かであると読者が思わないように指定されています。テーブルは 1 つのテーブルにまとめることができます) 、なぜ分離する必要があるのですか!)。

生徒登録

生徒登録は、ポイントの追加、削除、確認・修正、送信といった一般的な操作です。学生登録の簡単なコード例は次のとおりです:

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
}
ログイン後にコピー

Yii2 の使用経験がある人なら誰でも、User クラスと Student クラス ベースのルールをすぐに設定できると思います。データベースのフィールド制約に関する方法を書き留めます。たとえば、User クラス ファイルの内容は次のようになります:

namespace app\models;
class User extends \yii\db\ActiveRecord
{
 public function rules()
 {
  return [   [["username", "password", "status",], "required"],
   ["username", "unique"],
   // other rules
  ];
 }
 // other method
}
ログイン後にコピー

データの検証ルールを定義します。これは、ほとんどの人がこのファイルに対して抱く第一印象です。印象: 不正なデータを撃退し、通常のデータがシステムに入るのを許可します。セキュリティ対策では、完全なルールを定義し、データを完全に検証するように努める必要があります。また、すべての Yii2 開発者が組み込みのコアバリデーターに精通することをお勧めします。

情報の変更

情報の変更も、一般的な追加、削除、確認、および変更操作です。実装コードと登録には大きな違いはなく、ここでは 2 点だけ説明します:

1. ユーザー パスワードの検証

登録時にユーザー パスワードが検証されます。ユーザーのパスワードが 8 ~ 16 桁であるかどうかに関係なく、パスワード ルールは

["password", "string", "length" => [8, 16]] になります。パスワードを平文で保存することはお勧めできません。データベースに挿入する際には、少なくとも MD5 暗号化が実行され、パスワードは 32 ビットになります。ユーザーが情報を変更する際にパスワードを変更しなかったと仮定し、再度保存すると、パスワード規則の検証エラー(長さが一致しない)が発生し、保存できません。

この問題を解決するにはどうすればよいですか? Yii のドキュメントを調べてみると、ルール内の when 属性が役に立つことがわかりました。考えられる検証ルールの 1 つは次のとおりです。

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はパスワード値としてデータベースに直接保存されます。この操作により連鎖反応が発生しました。ユーザーが再度ログインすると、暗号化されたパスワードがデータベース内の平文パスワードと一致せず、トムはシステムにログインできなくなりました。厄介なのは、トムが厄介者で、ログインできなくなった後は一日中カスタマー サービスに嫌がらせをするので、心配するのは簡単ではありません。

この状況を防ぐにはどうすればよいでしょうか?解決策の 1 つは、パスワードの変更を防ぐことです。

unset($data["password"]); 
$user->load($data);
// 或者
$password = $user->password;
$user->load($data);
$user->password = $password;
ログイン後にコピー

ユーザーが入力したパスワードをフィルターで除外すると、パスワードを非公開で変更する問題は解決されます。

しかし、問題はまだ終わっていません。トムは性別や ID カードなどの他のフィールドを変更することができます。さらに深刻な状況は、student の user_id を変更することで、任意の学生の情報を変更できることです。問題は深刻であり、脆弱性は直ちに修正される必要があります。

可以按照密码的方法,逐个屏蔽受保护属性,但显得啰嗦难看(虽然好使)。如果受保护属性多,可以仅允许白名单进入,具体操作为:新增一个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基于非递归算法实现先序、中序及后序遍历二叉树操作的示例

PHP使用两个栈实现队列功能的方法的讲解

以上がYii2のシナリオと検証ルールの詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート