Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion system/Validation/Validation.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@
*/
class Validation implements ValidationInterface
{
/**
* Rules whose parameter is a reference to another field name.
* Only for these rules the parameter is looked up in the field rules
* to resolve the label of the referenced field.
*
* @var list<string>
*/
private const FIELD_REFERENCE_RULES = [
'matches',
'differs',
'required_with',
'required_without',
];

/**
* Files to load with validation functions.
*
Expand Down Expand Up @@ -873,7 +887,10 @@ protected function getErrorMessage(

$args = [
'field' => ($label === null || $label === '') ? $field : lang($label),
'param' => isset($this->rules[$param]['label']) ? lang($this->rules[$param]['label']) : $param,
'param' => in_array($rule, self::FIELD_REFERENCE_RULES, true)
&& isset($this->rules[$param]['label'])
? lang($this->rules[$param]['label'])
: $param,
'value' => $value ?? '',
];

Expand Down
44 changes: 44 additions & 0 deletions tests/system/Validation/ValidationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1858,6 +1858,50 @@ public function testNestedArrayThrowsException(): void
], $this->validation->getErrors());
}

public function testParamIsNotResolvedAsFieldLabelForNonFieldReferenceRules(): void
{
$rules = [
'secret' => [
'label' => 'Internal Secret Field',
'rules' => 'required',
],
'name' => [
'label' => 'Name',
'rules' => 'required|min_length[secret]',
],
];

$this->validation->setRules($rules);

$this->assertFalse($this->validation->run(['name' => 'a', 'secret' => 'x']));
$this->assertSame(
['name' => 'The Name field must be at least secret characters in length.'],
$this->validation->getErrors(),
);
}

public function testParamResolvesFieldLabelForFieldReferenceRules(): void
{
$rules = [
'password' => [
'label' => 'Password',
'rules' => 'required',
],
'password_confirmation' => [
'label' => 'Password Confirmation',
'rules' => 'matches[password]',
],
];

$this->validation->setRules($rules);

$this->assertFalse($this->validation->run(['password' => 'abc', 'password_confirmation' => 'def']));
$this->assertSame(
['password_confirmation' => 'The Password Confirmation field does not match the Password field.'],
$this->validation->getErrors(),
);
}

public function testRuleWithLeadingAsterisk(): void
{
$data = [
Expand Down
1 change: 1 addition & 0 deletions user_guide_src/source/changelogs/v4.7.5.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Bugs Fixed
- **Honeypot:** Fixed a bug where bot detection returned an HTTP 500 response instead of 403 (Forbidden).
- **I18n:** Fixed a bug where ``Time::today()``, ``Time::yesterday()``, and ``Time::tomorrow()`` ignored the specified ``$timezone`` and ``setTestNow()`` when calculating the day.
- **Logger:** Fixed a bug where interpolating a log message with array or non-stringable context values could raise PHP warnings or errors.
- **Validation:** Fixed a bug where a rule parameter that was not a field reference (e.g., a numeric limit) could resolve another field's label and leak it into the error message when it matched a defined field name. Label substitution now only applies to field-referencing rules (``matches``, ``differs``, ``required_with``, ``required_without``).

See the repo's
`CHANGELOG.md <https://github.com/codeigniter4/CodeIgniter4/blob/develop/CHANGELOG.md>`_
Expand Down
Loading