diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md
index 656fc8de40..c5c3d545ff 100644
--- a/framework/CHANGELOG.md
+++ b/framework/CHANGELOG.md
@@ -43,6 +43,7 @@ Yii Framework 2 Change Log
- Bug #19454: Fix PDO exception code not properly passed to `yii\db\Exception` (Roguyt)
- Bug #19477: cast shell_exec() output to string (schmunk42)
- Bug #19481: Exception is always empty in ErrorHandler when handling fatal error (Renkas)
+- Bug #19462: Fix validator client options to encode HTML tags (bizley)
2.0.45 February 11, 2022
------------------------
diff --git a/framework/captcha/CaptchaValidator.php b/framework/captcha/CaptchaValidator.php
index 9bcedca449..1a725386e0 100644
--- a/framework/captcha/CaptchaValidator.php
+++ b/framework/captcha/CaptchaValidator.php
@@ -9,6 +9,7 @@ namespace yii\captcha;
use Yii;
use yii\base\InvalidConfigException;
+use yii\helpers\Json;
use yii\validators\ValidationAsset;
use yii\validators\Validator;
@@ -89,7 +90,7 @@ class CaptchaValidator extends Validator
ValidationAsset::register($view);
$options = $this->getClientOptions($model, $attribute);
- return 'yii.validation.captcha(value, messages, ' . json_encode($options, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ');';
+ return 'yii.validation.captcha(value, messages, ' . Json::htmlEncode($options) . ');';
}
/**
diff --git a/framework/validators/BooleanValidator.php b/framework/validators/BooleanValidator.php
index ac8e334ea6..aea5a11db4 100644
--- a/framework/validators/BooleanValidator.php
+++ b/framework/validators/BooleanValidator.php
@@ -8,6 +8,7 @@
namespace yii\validators;
use Yii;
+use yii\helpers\Json;
/**
* BooleanValidator checks if the attribute value is a boolean value.
@@ -76,7 +77,7 @@ class BooleanValidator extends Validator
ValidationAsset::register($view);
$options = $this->getClientOptions($model, $attribute);
- return 'yii.validation.boolean(value, messages, ' . json_encode($options, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ');';
+ return 'yii.validation.boolean(value, messages, ' . Json::htmlEncode($options) . ');';
}
/**
diff --git a/framework/validators/CompareValidator.php b/framework/validators/CompareValidator.php
index fbe4d2cbe2..b94d498c6a 100644
--- a/framework/validators/CompareValidator.php
+++ b/framework/validators/CompareValidator.php
@@ -10,6 +10,7 @@ namespace yii\validators;
use Yii;
use yii\base\InvalidConfigException;
use yii\helpers\Html;
+use yii\helpers\Json;
/**
* CompareValidator compares the specified attribute value with another value.
@@ -234,7 +235,7 @@ class CompareValidator extends Validator
ValidationAsset::register($view);
$options = $this->getClientOptions($model, $attribute);
- return 'yii.validation.compare(value, messages, ' . json_encode($options, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ', $form);';
+ return 'yii.validation.compare(value, messages, ' . Json::htmlEncode($options) . ', $form);';
}
/**
diff --git a/framework/validators/FileValidator.php b/framework/validators/FileValidator.php
index 2d67ac60cb..65f8897cad 100644
--- a/framework/validators/FileValidator.php
+++ b/framework/validators/FileValidator.php
@@ -432,7 +432,7 @@ class FileValidator extends Validator
{
ValidationAsset::register($view);
$options = $this->getClientOptions($model, $attribute);
- return 'yii.validation.file(attribute, messages, ' . Json::encode($options) . ');';
+ return 'yii.validation.file(attribute, messages, ' . Json::htmlEncode($options) . ');';
}
/**
diff --git a/framework/validators/FilterValidator.php b/framework/validators/FilterValidator.php
index d24131a971..0a0ec5ba9a 100644
--- a/framework/validators/FilterValidator.php
+++ b/framework/validators/FilterValidator.php
@@ -8,6 +8,7 @@
namespace yii\validators;
use yii\base\InvalidConfigException;
+use yii\helpers\Json;
/**
* FilterValidator converts the attribute value according to a filter.
@@ -93,7 +94,7 @@ class FilterValidator extends Validator
ValidationAsset::register($view);
$options = $this->getClientOptions($model, $attribute);
- return 'value = yii.validation.trim($form, attribute, ' . json_encode($options, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ', value);';
+ return 'value = yii.validation.trim($form, attribute, ' . Json::htmlEncode($options) . ', value);';
}
/**
diff --git a/framework/validators/ImageValidator.php b/framework/validators/ImageValidator.php
index 0a06dd75f4..d7121f5b6c 100644
--- a/framework/validators/ImageValidator.php
+++ b/framework/validators/ImageValidator.php
@@ -8,6 +8,7 @@
namespace yii\validators;
use Yii;
+use yii\helpers\Json;
use yii\web\UploadedFile;
/**
@@ -166,7 +167,7 @@ class ImageValidator extends FileValidator
{
ValidationAsset::register($view);
$options = $this->getClientOptions($model, $attribute);
- return 'yii.validation.image(attribute, messages, ' . json_encode($options, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ', deferred);';
+ return 'yii.validation.image(attribute, messages, ' . Json::htmlEncode($options) . ', deferred);';
}
/**
diff --git a/framework/validators/RangeValidator.php b/framework/validators/RangeValidator.php
index bcde4a1309..9d11fdc20e 100644
--- a/framework/validators/RangeValidator.php
+++ b/framework/validators/RangeValidator.php
@@ -10,6 +10,7 @@ namespace yii\validators;
use Yii;
use yii\base\InvalidConfigException;
use yii\helpers\ArrayHelper;
+use yii\helpers\Json;
/**
* RangeValidator validates that the attribute value is among a list of values.
@@ -111,7 +112,7 @@ class RangeValidator extends Validator
ValidationAsset::register($view);
$options = $this->getClientOptions($model, $attribute);
- return 'yii.validation.range(value, messages, ' . json_encode($options, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ');';
+ return 'yii.validation.range(value, messages, ' . Json::htmlEncode($options) . ');';
}
/**
diff --git a/framework/validators/RequiredValidator.php b/framework/validators/RequiredValidator.php
index 646357ace3..03a7b1b415 100644
--- a/framework/validators/RequiredValidator.php
+++ b/framework/validators/RequiredValidator.php
@@ -8,6 +8,7 @@
namespace yii\validators;
use Yii;
+use yii\helpers\Json;
/**
* RequiredValidator validates that the specified attribute does not have null or empty value.
@@ -93,7 +94,7 @@ class RequiredValidator extends Validator
ValidationAsset::register($view);
$options = $this->getClientOptions($model, $attribute);
- return 'yii.validation.required(value, messages, ' . json_encode($options, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ');';
+ return 'yii.validation.required(value, messages, ' . Json::htmlEncode($options) . ');';
}
/**
diff --git a/framework/validators/StringValidator.php b/framework/validators/StringValidator.php
index 3f44ce29de..4db6314e25 100644
--- a/framework/validators/StringValidator.php
+++ b/framework/validators/StringValidator.php
@@ -8,6 +8,7 @@
namespace yii\validators;
use Yii;
+use yii\helpers\Json;
/**
* StringValidator validates that the attribute value is of certain length.
@@ -168,7 +169,7 @@ class StringValidator extends Validator
ValidationAsset::register($view);
$options = $this->getClientOptions($model, $attribute);
- return 'yii.validation.string(value, messages, ' . json_encode($options, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . ');';
+ return 'yii.validation.string(value, messages, ' . Json::htmlEncode($options) . ');';
}
/**
diff --git a/framework/validators/TrimValidator.php b/framework/validators/TrimValidator.php
index 2e32db69c4..7426d195bd 100644
--- a/framework/validators/TrimValidator.php
+++ b/framework/validators/TrimValidator.php
@@ -7,6 +7,8 @@
namespace yii\validators;
+use yii\helpers\Json;
+
/**
* This class converts the attribute value(s) to string(s) and strip characters.
*
@@ -65,7 +67,7 @@ class TrimValidator extends Validator
ValidationAsset::register($view);
$options = $this->getClientOptions($model, $attribute);
- return 'value = yii.validation.trim($form, attribute, ' . json_encode($options) . ', value);';
+ return 'value = yii.validation.trim($form, attribute, ' . Json::htmlEncode($options) . ', value);';
}
/**
diff --git a/tests/framework/validators/BooleanValidatorTest.php b/tests/framework/validators/BooleanValidatorTest.php
index 9835422ebf..4c183a0de0 100644
--- a/tests/framework/validators/BooleanValidatorTest.php
+++ b/tests/framework/validators/BooleanValidatorTest.php
@@ -85,7 +85,7 @@ class BooleanValidatorTest extends TestCase
$obj->attrD = [];
$this->assertEquals(
- 'yii.validation.boolean(value, messages, {"trueValue":true,"falseValue":false,"message":"attrB must be either \"true\" or \"false\".","skipOnEmpty":1,"strict":1});',
+ 'yii.validation.boolean(value, messages, {"trueValue":true,"falseValue":false,"message":"attrB must be either \u0022true\u0022 or \u0022false\u0022.","skipOnEmpty":1,"strict":1});',
$validator->clientValidateAttribute($obj, 'attrB', new ViewStub())
);
}
diff --git a/tests/framework/validators/RequiredValidatorTest.php b/tests/framework/validators/RequiredValidatorTest.php
index 1d4fde051d..fd7cc1811e 100644
--- a/tests/framework/validators/RequiredValidatorTest.php
+++ b/tests/framework/validators/RequiredValidatorTest.php
@@ -7,6 +7,7 @@
namespace yiiunit\framework\validators;
+use yii\base\Model;
use yii\validators\RequiredValidator;
use yiiunit\data\validators\models\FakedValidationModel;
use yiiunit\TestCase;
@@ -66,4 +67,33 @@ class RequiredValidatorTest extends TestCase
$val->validateAttribute($m, 'attr_val');
$this->assertFalse($m->hasErrors('attr_val'));
}
+
+ public function testErrorClientMessage()
+ {
+ $validator = new RequiredValidator(['message' => 'error for {attribute}']);
+
+ $obj = new ModelForReqValidator();
+
+ $this->assertEquals(
+ 'yii.validation.required(value, messages, {"message":"\u003Cstrong\u003Eerror\u003C\/strong\u003E for \u003Cb\u003EAttr\u003C\/b\u003E"});',
+ $validator->clientValidateAttribute($obj, 'attr', new ViewStub())
+ );
+ }
+}
+
+class ModelForReqValidator extends Model
+{
+ public $attr;
+
+ public function rules()
+ {
+ return [
+ [['attr'], 'required'],
+ ];
+ }
+
+ public function attributeLabels()
+ {
+ return ['attr' => 'Attr'];
+ }
}