When configuring a url form field (UrlField) or validating a field with validate="url" (UrlRule) or filtering with filter="url" (UrlFilter), the relative XML attribute is improperly evaluated as a raw SimpleXMLElement object in boolean expressions instead of being cast to a string or boolean:
UrlField::getLayoutData() (libraries/src/Form/Field/UrlField.php line 71):$inputType = $this->element['relative'] ? 'type="text"' : 'type="url"';UrlRule::test() (libraries/src/Form/Rule/UrlRule.php line 85):if ($urlParts === false || !$element['relative']) {UrlFilter::filter() (libraries/src/Form/Filter/UrlFilter.php lines 64 & 77):if (
((string) $element['type'] === 'url' && !$protocol && !$element['relative'])
|| ((string) $element['type'] !== 'url' && !$protocol)
) {
...
} elseif (!$protocol && $element['relative']) {
...
}In PHP, a non-empty SimpleXMLElement object (such as one representing relative="false") evaluates to true when evaluated directly in a boolean context.
As a result, when relative="false" is explicitly set on a field XML definition:
UrlField renders with <input type="text"> instead of <input type="url">.UrlRule allows scheme-less relative paths (e.g. /my-path) to pass validation when they should fail.UrlFilter skips prepending the default external protocol (http://) and instead treats the value as an internal relative URL, prepending Uri::root(true).url field where relative="false":<field
name="external_website"
type="url"
label="External Website"
relative="false"
validate="url"
filter="url"
/>$form->getInput('external_website') and inspect the generated <input> tag.'/contact-us') via $form->validate(['external_website' => '/contact-us']) or (new \Joomla\CMS\Form\Rule\UrlRule())->test($element, '/contact-us').'example.com') via (new \Joomla\CMS\Form\Filter\UrlFilter())->filter($element, 'example.com').5.4
UrlField renders <input type="url" ...> when relative="false" (or when relative is not specified).UrlRule::test() returns false (validation failure) for relative paths without a scheme (e.g. '/contact-us') when relative="false".UrlFilter::filter() treats scheme-less inputs as external URLs and prepends http:// when relative="false".UrlField evaluates $this->element['relative'] as truthy and renders <input type="text" ...>.UrlRule::test() evaluates !$element['relative'] as false, bypassing the missing scheme check and accepting relative URLs as valid.UrlFilter::filter() enters the elseif (!$protocol && $element['relative']) block and incorrectly prepends the site root path instead of the external protocol.In UrlRule.php, other attributes are properly cast before evaluation (e.g. (string) $element['required'] === 'true' and (string) $element['disableXssCheck'] !== 'true').
$relative should be checked consistently, for example:
$relative = isset($element['relative']) && !in_array((string) $element['relative'], ['false', '0', 'off'], true);or (string) $element['relative'] === 'true' || (string) $element['relative'] === 'relative' || (string) $element['relative'] === '1'.
Additionally, UrlField could benefit from property getter/setter support for $relative in line with other form field classes.
| Labels |
Added:
No Code Attached Yet
|
||