Version 4.7.6

Release Date: Unreleased

4.7.6 release of CodeIgniter4

BREAKING

Message Changes

  • Added the CLI.inputEnded language string.

  • Added the Format.invalidXMLValue language string.

Changes

  • Cache: Added an optional $path parameter to FileVarExportHandler::__construct() so the cache files can be stored in a custom directory.

  • HTTP: Added ContentSecurityPolicy::addDefaultSrc() to allow appending sources to the default-src directive.

Deprecations

Bugs Fixed

  • CLI: Fixed a bug where CLI::promptByMultipleKeys() accepted a key missing from the options when it was below the last key, returning an empty selection, rejected a key above the last one when the options were not in key order, and offered 0 as the default when the first key was not 0.

  • CLI: Fixed a bug where a prompt asked again forever when its input was piped or redirected and ran out before a valid answer: CLI::prompt() and CLI::promptByKey() whose default fails the validation rules, and CLI::promptByMultipleKeys() whose options have string keys. They now throw a CLIException. The new InputOutput::isAtEnd() tells that end of the input from an empty line. Pressing Ctrl+D at a terminal still asks again.

  • Commands: Fixed a bug where generator commands did not sort the imports of a template with CRLF line endings.

  • Database: Fixed reconnect() so a replaced socket does not keep the transaction that died with the old connection. transDepth is cleared and the transaction status is failed before the new connection is opened, so a failed reconnect cannot still report success. OCI8 commit mode returns to autocommit. transComplete() does not report success. This applies when ping() reports the connection lost; PostgreSQL’s pg_ping() reconnects a broken connection itself, so it is not covered.

  • Database: Fixed MySQLi errno 1213 (ER_LOCK_DEADLOCK) so a following write through query(), simpleQuery() or the Query Builder on the victim connection does not autocommit, and transCommit() rolls back and returns false after InnoDB has rolled the victim transaction back. Prepared queries and errno 1205 are unchanged.

  • 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 a bug in ContentSecurityPolicy where a numeric source such as '0' threw a TypeError, and a space-separated directive string in Config\\ContentSecurityPolicy was emitted as one unquoted source.

  • HTTP: Fixed a regression in v4.7.0 where calling ContentSecurityPolicy::reportOnly() after the policy was created did not apply to array sources from Config\\ContentSecurityPolicy, so they stayed in the enforced Content-Security-Policy header alongside the Content-Security-Policy-Report-Only header.

  • HTTP: Fixed a bug in ContentSecurityPolicy::setDefaultSrc() where passing an array of URIs resulted in an invalid 'Array' directive.

  • HTTP: Fixed a bug where IncomingRequest did not read the request body when PHP’s post_max_size was set to 0 or -1 (unlimited).

  • 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.

  • HTTP: Fixed a bug where Negotiate::media() threw an ErrorException when the Accept header contained a value without a subtype, such as json or an empty list element. Such values are now ignored.

  • HTTP: Fixed a bug where Negotiate could select a value that the request header excluded with q=0 through a wildcard or a broader range. A q=0 range now excludes every value it matches, such as text/html and text/html;charset=utf-8 for text/*;q=0, or en-US for en;q=0, unless a more specific range in the header accepts the value. For example, Accept-Encoding: gzip;q=0, * no longer selects gzip.

  • HTTP: Fixed stale $_REQUEST values after SiteURIFactory normalizes GET parameters, so Validation::withRequest() reads the normalized values while unrelated REQUEST entries are preserved.

  • I18n: Fixed a regression in v4.7.1 where Time and TimeLegacy lost their timezone, locale and __toString() format after unserialize(), so methods such as difference() and getTimezoneName() threw an Error.

  • Routing: Corrected the PHPDoc callback type of RouteCollection::group() to preserve the concrete collection type, allowing callbacks typed to a RouteCollection subclass to pass static analysis.

  • 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 for a complete list of bugs fixed.