diff --git a/system/Helpers/form_helper.php b/system/Helpers/form_helper.php index dee1f001365b..b030b2f06009 100644 --- a/system/Helpers/form_helper.php +++ b/system/Helpers/form_helper.php @@ -11,6 +11,7 @@ * the LICENSE file that was distributed with this source code. */ +use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\Validation\Exceptions\ValidationException; use Config\App; use Config\Validation; @@ -547,27 +548,25 @@ function form_close(string $extra = ''): string if (! function_exists('set_value')) { /** - * Form Value - * * Grabs a value from the POST array for the specified field so you can * re-populate an input field or textarea * - * @param string $field Field name - * @param list|string $default Default value - * @param bool $htmlEscape Whether to escape HTML special characters or not + * @param string $field Field name + * @param list|scalar|Stringable|null $default Default value + * @param bool $htmlEscape Whether to escape HTML special characters or not * * @return list|string */ function set_value(string $field, $default = '', bool $htmlEscape = true): array|string { + /** @var IncomingRequest $request */ $request = service('request'); - // Try any old input data we may have first - $value = $request->getOldInput($field); - - $value ??= $request->getPost($field) ?? $default; + $value = $request->getOldInput($field) + ?? $request->getPost($field) + ?? (is_array($default) ? $default : (string) $default); - return ($htmlEscape) ? esc($value) : $value; + return $htmlEscape ? esc($value) : $value; } } diff --git a/tests/system/Helpers/FormHelperTest.php b/tests/system/Helpers/FormHelperTest.php index c24d34b04a3e..7ed8c8668123 100644 --- a/tests/system/Helpers/FormHelperTest.php +++ b/tests/system/Helpers/FormHelperTest.php @@ -22,10 +22,12 @@ use Config\Filters; use Config\Services; use PHPUnit\Framework\Attributes\BackupGlobals; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\PreserveGlobalState; use PHPUnit\Framework\Attributes\RunInSeparateProcess; use PHPUnit\Framework\Attributes\WithoutErrorHandler; +use Stringable; /** * @internal @@ -867,6 +869,38 @@ public function testSetValue(): void $this->assertSame('baz', set_value('foo', 'baz')); } + #[DataProvider('provideSetValueCastsNonArrayDefaultToString')] + public function testSetValueCastsNonArrayDefaultToString(mixed $default, string $expected): void + { + $this->assertSame($expected, set_value('foo', $default)); + } + + /** + * @return iterable + */ + public static function provideSetValueCastsNonArrayDefaultToString(): iterable + { + $stringable = self::createStub(Stringable::class); + $stringable->method('__toString')->willReturn(''); + + yield 'int' => [1, '1']; + + yield 'float' => [1.5, '1.5']; + + yield 'true' => [true, '1']; + + yield 'false' => [false, '']; + + yield 'null' => [null, '']; + + yield 'stringable' => [$stringable, '<bar>']; + } + + public function testSetValueKeepsArrayDefault(): void + { + $this->assertSame(['a', 'b'], set_value('foo', ['a', 'b'])); + } + public function testSetSelect(): void { $_SESSION['_ci_old_input']['post']['foo'] = 'bar'; diff --git a/user_guide_src/source/changelogs/v4.7.6.rst b/user_guide_src/source/changelogs/v4.7.6.rst index dc63b43dc354..75e6f890047c 100644 --- a/user_guide_src/source/changelogs/v4.7.6.rst +++ b/user_guide_src/source/changelogs/v4.7.6.rst @@ -33,19 +33,11 @@ Bugs Fixed ********** - **Commands:** Fixed a bug where generator commands did not sort the imports of a template with CRLF line endings. -- **Format:** Fixed ``XMLFormatter`` so that an array key that becomes empty after - sanitization no longer triggers a ``ValueError``; the fallback tag name ``item`` - is used instead. Values that cannot be converted to a string, such as objects - not implementing ``Stringable``, now throw a ``FormatException`` instead of a - fatal ``Error``. +- **Format:** Fixed ``XMLFormatter`` so that an array key that becomes empty after sanitization no longer triggers a ``ValueError``; the fallback tag name ``item`` is used instead. Values that cannot be converted to a string, such as objects not implementing ``Stringable``, now throw a ``FormatException`` instead of a fatal ``Error``. +- **Helpers:** Fixed a regression in v4.7.5 where ``set_value()`` threw a ``TypeError`` when the default value was not a string or an array, such as an integer, a float, ``null``, or a ``Stringable`` object. Such values are now converted to a string. - **HTTP:** Fixed stale ``$_REQUEST`` values after ``SiteURIFactory`` normalizes GET parameters, so ``Validation::withRequest()`` reads the normalized values while unrelated REQUEST entries are preserved. -- **HTTP:** Fixed a bug where ``IncomingRequest::isSecure()`` did not - recognize ``https`` in the ``X-Forwarded-Proto`` header from a trusted - proxy when the value contained uppercase letters or surrounding - whitespace, or was represented as a single-element array. -- **Security:** Fixed a bug where a valid JSON request body that is not an object - (for example a JSON array) was corrupted after CSRF verification when the - token was sent via the ``X-CSRF-TOKEN`` header. +- **HTTP:** Fixed a bug where ``IncomingRequest::isSecure()`` did not recognize ``https`` in the ``X-Forwarded-Proto`` header from a trusted proxy when the value contained uppercase letters or surrounding whitespace, or was represented as a single-element array. +- **Security:** Fixed a bug where a valid JSON request body that is not an object (for example a JSON array) was corrupted after CSRF verification when the token was sent via the ``X-CSRF-TOKEN`` header. See the repo's `CHANGELOG.md `_ diff --git a/user_guide_src/source/helpers/form_helper.rst b/user_guide_src/source/helpers/form_helper.rst index 9a2d9f026abb..36d19374a774 100644 --- a/user_guide_src/source/helpers/form_helper.rst +++ b/user_guide_src/source/helpers/form_helper.rst @@ -452,10 +452,10 @@ The following functions are available: .. php:function:: set_value($field[, $default = ''[, $html_escape = true]]) :param string $field: Field name - :param string $default: Default value + :param mixed $default: Default value. An array is returned as is, any other value is converted to a string. :param bool $html_escape: Whether to turn off HTML escaping of the value :returns: Field value - :rtype: string + :rtype: array|string Permits you to set the value of an input or textarea element. You must supply the field name via the first parameter of the function. The