Detailed explanation of scenario of scenario and validation rule of rule in Yii2

  • 2021-09-04 23:38:32
  • OfStack

Preface

Scene, as its name implies, is a scene and a scene. There is also a scene in yii2, which is similar to the meaning of the scene you understand.

Necessary functions of a system that interacts with users include collecting user data, checking and processing. In actual business, it is often necessary to store data persistently. For security reasons, developers should firmly grasp the principle that "the input from the client is untrustworthy", and the data transmitted from the client should be filtered and cleaned before being stored or transmitted to the internal system.

Yii2 recommends the Model class for collecting and validating user data, with the persisted ActiveRecord class as a subclass. The load and validate methods of the Model class are used to collect and validate client data, respectively. What data should be collected and what data should be validated in what scenarios are the topics of this article: scenarios (scenario) and validation rules (rule).

The following words are not much to say, let's take a look at the detailed introduction with this site 1.

System structure

Firstly, a simple business system is introduced: there are two roles of students and teachers in the system, and three tables are used in the database to save role information:

user: [id, username, password, status, other common attributes]

student: [id, user_id, student_no, grade, class, other student attributes]

teacher: [id, user_id, work_no, title, telphone, other instructor attributes]

The actual business is not limited to the addition, deletion, check and change of these three tables. In order to simplify the problem, only the data changes of user and student are discussed in the future (the teacher table is given so that readers don't think that the person who designed the database is brain-dead: it can be put into one table, so why disassemble it!) .

Student registration

Student registration is a typical operation of adding, deleting, checking and changing, and sending sub-questions. A brief code example of student enrollment is as follows:


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
}

I believe that people who have experience in using Yii2 can quickly write rules methods of User and Student classes according to the field constraints of the database. For example, the contents of an User class file might be as follows:


namespace app\models;
class User extends \yii\db\ActiveRecord
{
 public function rules()
 {
  return [   [["username", "password", "status",], "required"],
   ["username", "unique"],
   // other rules
  ];
 }
 // other method
}

Defining validation rules for data is most people's first impression of rules, and it is a good impression: it calls back illegal data and lets normal data enter the system. Security practices should try to define complete rules and fully verify data. It is also recommended that every Yii2 developer be familiar with the built-in core validator.

Modify information

Modifying information is also a typical operation of adding, deleting, checking and modifying. There is little difference between the implementation code and the registration, so only two points are discussed here:

1. Verification of user password

When registering, it will check whether the user password is 8-16 digits. The password rules may be: ["password", "string", "length" => [8, 16]] . It is not advisable to save passwords in clear text. At least MD5 encryption will be done when inserting the database, and password will become 32 bits. Assuming that the user did not modify the password when modifying the information, the password rule verification error (length does not conform) when saving again, and cannot be saved!

How to solve this problem? Looking through the Yii document, I found that the when attribute in the rule can save the field. One possible validation rule is:


public function rules()
{
 return [
   ["password", "string", "length" => [8, 16], 'when' => function ($model) {
    return $model->isNewRecord;
   }] , 
   // other rules
  ];

The password field is only verified when registering (adding data). Problem solving, perfect!

2. Prevent users from changing passwords privately

Suppose there is a clever guy (such as Tom) who discovers that the system is made with Yii framework and wants to do a little damage to show off his level. When sending the form to modify the information, Tom added & password=12345678. System usage $user->load($data) Collect user input and update the password field, resulting in the following consequences: the password field is not verified when the rules setting is updated, and 12345678 is directly saved in the database as the value of password. This operation has a chain reaction: When the user logs in again, the encrypted password does not match the plaintext password in the database, which makes Tom unable to log in to the system. What is annoying is that Tom is a thorn. He can't log in and harass customer service all day.

How to prevent this from happening? One solution is to prevent password changes:


unset($data["password"]); 
$user->load($data);
//  Or 
$password = $user->password;
$user->load($data);
$user->password = $password;

The password entered by the user is filtered out, and the problem of changing the password without permission is solved.

But the problem is not over: Tom can turn to other fields, such as gender, ID card and so on. More seriously, you can change the information of any student by modifying user_id in student. Things are 10 points serious, and the loopholes need to be fixed immediately.

Protected attributes can be shielded one by one in the way of passwords, but it is ugly (although it works well). If there are many protected attributes, only white list can be allowed to enter. The specific operation is to add one UpdateInfoForm class to inherit Model, and the attributes are the total of white list attributes. Filter user data with UpdateInfoForm class, and update it to user and student after passing the verification:


$form = new UpdateInfoForm();
$form->load($data);
if ($form->validate()) {
 $user->load($form->attributes);
 $student->load($form->attributes);
 // next biz
}

This method is more elegant, but it costs a lot to think carefully: attributes and validation rules should be written again and again; user and student are saved by repeating the verification properties. This method looks elegant, but in fact it is redundant and inefficient.

The appearance of scenario perfectly solves the above problems.

Scene (scenario)

Analyzing the above problems, we will find that the key points are batch assignment (massive assignment) and data verification (validate). If you specify assignment fields and verification rules for different scenarios, the problem will be solved.

scenario in Yii has two concepts: security attribute and active attribute. Security attributes are used in load method of batch assignment, and only security attributes can be assigned; Active attributes are used in the validate method of rule validation. Attributes in the active attribute set that define the validation rule will be validated. The relationship between active attributes and security attributes is that security attributes are a subset of active attributes.

The\ yii\ base\ Model class defines the default scenario: SCENARIO_DEFAULT (the value is default). By default, the properties that appear in the rules method are both active and safe (this sentence is basically correct, see later explanation). Specifying active attributes, security attributes, and validators for different scenarios can be achieved by overriding either senarios or rules (almost every Model class overrides the rules method, and senarios is used less).

rules

Look at the rules method first. The default attribute plus validator definition makes each attribute both safe and active. If you want an attribute not to be a safe attribute (you can't assign it in batches through load), add an exclamation point before the attribute name! That's enough. For example, the user_id field in student:


public function rules()
{
 return [
  ["!user_od", "required"],
  ["!user_id", "integer"],
  ["!user_od", "unique"],
  // other rules
 ];
}

user_id is an active attribute that is verified when written to the database. However, it is not a security attribute, so it can't be assigned by load method, which solves the potential safety hazard.

Look at the rules method to distinguish validator rules according to scenarios: when defining validators, the on attribute specifies which scenarios the rules take effect, while the except attribute excludes one scenario (if on and except are not specified, the rules take effect for all scenarios). For example:


public function rules()
{
 return [
  ["password", "string", "length" => [8, 16], "on" => ["signup"]], //  Only in signup Scene is only verified 
  ["status", "integer", "except" => ["signup"], //  Except for signup Scenario, everything else is verified 
  // other rules
 ];
}

Adding exclamation mark and on/except attribute on the original basis, it is very simple to define unsafe attribute and specify verification rules in different scenarios.

scenarios

Another way to define security and active attributes more clearly is to override the scenarios method. The scenarios method returns an array whose key is the scene name and whose value is the collection of active attributes (including security attributes). For example, the possible implementation of the student table is as follows:


public function scenarios()
{
 return [
  self::SCENARIO_DEFAULT => ["!user_id", "grade", "class", xxxx],
  "update" => ["grade", "class", xxxx],
 ];
}

By default (student registration), grade and class information are security attributes, but user_id is not, which can only be assigned within the program and verified when inserting data; When modifying information, user_id is not an active attribute, can neither be assigned in batches nor need to be verified (in fact, it should not be changed).

scenarios method can only define active attributes and security attributes, but cannot define verification rules, so it needs to be used together with rules.

Summarize

Gold affirms the perfect data verification rules

When the business is complex, define multiple scenarios, and carefully define security attributes and verification rules for each scenario

Preferential use of rules; When there are many attributes and rules is complex, the security attributes and active attributes can be quickly sorted out with scenarios method

Reference

http://www.yiiframework.com/doc-2.0/guide-input-validation.html


Related articles: