Maison > développement back-end > tutoriel php > Explication détaillée des scénarios et des règles de vérification dans Yii2

Explication détaillée des scénarios et des règles de vérification dans Yii2

jacklove
Libérer: 2023-04-02 08:06:01
original
3915 Les gens l'ont consulté

Les règles de Yii2 sont utilisées pour vérifier les attributs du modèle. Les utilisateurs de scénarios définissent les modèles qui doivent être vérifiés dans différents scénarios. L'article suivant présente principalement des informations pertinentes sur les scénarios (scénarios) et les règles de vérification (règles) dans Yii2. l'article le présente en détail à travers un exemple de code, les amis dans le besoin peuvent s'y référer.

Avant-propos

La scène, comme son nom l'indique, est une scène, une scène. Il y a aussi des scènes dans yii2, qui ont des significations similaires à celles que vous comprenez.

Les fonctions essentielles d'un système qui interagit avec les utilisateurs comprennent la collecte des données utilisateur, la vérification et le traitement. Dans la réalité des affaires, les données doivent souvent être stockées de manière persistante. Pour des raisons de sécurité, les développeurs doivent bien comprendre le principe selon lequel « les données envoyées par le client ne sont pas fiables ». Les données envoyées par le client sont filtrées et nettoyées avant d'être stockées ou transférées vers le système interne.

Yii2 recommande d'utiliser la classe Model pour collecter et vérifier les données utilisateur, et la classe persistante ActiveRecord est sa sous-classe. Les méthodes de chargement et de validation de la classe Model sont utilisées respectivement pour collecter et vérifier les données client. Quelles données doivent être collectées et quelles données doivent être vérifiées dans quels scénarios sont les thèmes de cet article : scénarios et règles de vérification.

Pas grand chose à dire ci-dessous, suivons l'éditeur et jetons un œil à l'introduction détaillée.

Structure du système

Introduisez d'abord un système commercial simple : il y a deux rôles d'étudiants et d'enseignants dans le système, qui sont utilisé dans la base de données Trois tables sont créées pour enregistrer les informations de rôle :

utilisateur : [id, nom d'utilisateur, mot de passe, statut, autres attributs communs]

étudiant : [id, user_id, student_no, note , classe, autres attributs des élèves]

enseignant : [id, user_id, work_no, titre, téléphone, autres attributs de l'enseignant]

L'activité réelle ne se limite pas à l'ajout, la suppression, la requête et opérations de modification de ces trois tables. Afin de simplifier le problème, seules les modifications des données dans les tables utilisateur et étudiant seront discutées plus tard (la table professeur est donnée pour que les lecteurs ne pensent pas que la personne qui a conçu la base de données est stupide : elle peut être mise dans une seule table). , pourquoi devrait-il être séparé !).

Inscription des étudiants

L'inscription des étudiants est une opération typique d'ajout, de suppression, de vérification et de modification, et des sous-questions sont envoyées . Un bref exemple de code pour l'inscription des étudiants est le suivant :

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
}
Copier après la connexion

Je crois que toute personne ayant de l'expérience dans l'utilisation de Yii2 peut rapidement convertir les classes Utilisateur et Étudiant en fonction aux contraintes de champ de la base de données. Écrivez la méthode des règles. Par exemple, le contenu du fichier de classe Utilisateur peut être le suivant :

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

Définir les règles de validation des données. C'est la première impression de la plupart des gens. Il y a des règles, et c'est une très bonne impression : cela repousse les données illégales et permet aux données normales d'entrer dans le système. Les pratiques de sécurité doivent tenter de définir des règles complètes et de vérifier entièrement les données. Il est également recommandé à chaque développeur Yii2 de se familiariser avec les principaux validateurs intégrés.

Modifier les informations

La modification des informations est également une opération typique d'ajout, de suppression, de vérification et de modification. Il n'y a pas beaucoup de différence entre le code d'implémentation et l'inscription. Seuls deux points sont abordés ici :

1 Vérification du mot de passe de l'utilisateur

Lors de l'inscription, il sera vérifié. si le mot de passe de l'utilisateur comporte 8 à 16 chiffres, la règle du mot de passe peut être : ["password", "string", "length" => [8, 16]] . Il n'est pas conseillé d'enregistrer les mots de passe en texte clair Lors de l'insertion dans la base de données, au moins un cryptage MD5 sera effectué et le mot de passe deviendra 32 bits. Supposons que l'utilisateur ne change pas le mot de passe lors de la modification des informations. Lors de la nouvelle sauvegarde, l'erreur de vérification de la règle de mot de passe se produit (la longueur ne correspond pas) et ne peut pas être enregistrée !

Comment résoudre ce problème ? En parcourant la documentation Yii, j'ai découvert que l'attribut when dans les règles peut sauver la situation. Une règle de validation possible est la suivante :

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

Le champ du mot de passe n'est vérifié que lors de l'inscription (nouvelles données). Problème résolu, parfait !

2. Empêcher les utilisateurs de modifier leurs mots de passe en privé

Supposons qu'il y ait un gars intelligent (comme Tom) qui découvre que le système est construit à l'aide du framework Yii et veut faire des dégâts. Montrez vos compétences. Lors de l'envoi du formulaire pour modifier les informations, Tom ajoute &password=12345678. Le système utilise $user->load($data) pour collecter les entrées de l'utilisateur et mettre à jour le champ du mot de passe, ce qui entraîne les conséquences suivantes : le champ du mot de passe n'est pas vérifié lorsque les paramètres des règles sont mis à jour et 12345678 est directement enregistré dans la base de données comme valeur du mot de passe. Cette opération a provoqué une réaction en chaîne : lorsque l'utilisateur s'est à nouveau connecté, le mot de passe crypté ne correspondait pas au mot de passe en texte brut dans la base de données, empêchant Tom de se connecter au système. Le plus ennuyeux, c'est que Tom est une épine dans le pied. Après avoir été incapable de se connecter, il harcèle le service client à longueur de journée, ce qui n'est pas facile à craindre !

Comment éviter que cette situation ne se produise ? Une solution consiste à empêcher les changements de mot de passe :

unset($data["password"]); 
$user->load($data);
// 或者
$password = $user->password;
$user->load($data);
$user->password = $password;
Copier après la connexion

Filtrez les mots de passe saisis par les utilisateurs et le problème de la modification des mots de passe en privé est résolu.

Mais le problème n'est pas encore résolu : Tom peut se tourner pour modifier d'autres champs, comme le sexe, la carte d'identité, etc. Une situation plus grave est qu'en modifiant le user_id dans student, vous pouvez modifier les informations de n'importe quel étudiant. Le problème est grave et la vulnérabilité doit être corrigée immédiatement.

可以按照密码的方法,逐个屏蔽受保护属性,但显得啰嗦难看(虽然好使)。如果受保护属性多,可以仅允许白名单进入,具体操作为:新增一个UpdateInfoForm类继承Model,属性是白名单属性合计。用UpdateInfoForm类过滤用户数据,校验通过后再更新到user和student中:

$form = new UpdateInfoForm();
$form->load($data);
if ($form->validate()) {
 $user->load($form->attributes);
 $student->load($form->attributes);
 // next biz
}
Copier après la connexion

这种方式更优雅,但仔细一想代价不小:属性和验证规则要重复写一遍;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
 ];
}
Copier après la connexion

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
 ];
}
Copier après la connexion

在原来基础上新增感叹号和on/except属性,非常简便的就定义了非安全属性以及分场景指定校验规则。

scenarios

另外一种更清晰定义安全属性和活跃属性的做法是重写scenarios方法。scenarios方法返回一个数组,数组的键是场景名称,值是活跃属性集合(包饭安全属性)。例如student表的可能实现如下:

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

默认情形下(学生报名),年级、班级这些信息是安全属性,但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使用两个栈实现队列功能的方法的讲解

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal