TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _feature-105638-1732034075:
|
||||
|
||||
==============================================
|
||||
Feature: #105638 - Modify fetched page content
|
||||
==============================================
|
||||
|
||||
See :issue:`105638`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
With :issue:`103894` the new data processor :ref:`PageContentFetchingProcessor <feature-103894-1716544976>`
|
||||
has been introduced, to allow fetching page content based on the current page
|
||||
layout, taking the configured :php:`SlideMode` into account.
|
||||
|
||||
Fetching content has previously mostly been done via the `Content` content
|
||||
object. A common example looked like this:
|
||||
|
||||
.. code-block:: typoscript
|
||||
|
||||
page.20 = CONTENT
|
||||
page.20 {
|
||||
table = tt_content
|
||||
select {
|
||||
orderBy = sorting
|
||||
where = colPos=0
|
||||
}
|
||||
}
|
||||
|
||||
As mentioned in the linked changelog, using the `page-content` data processor,
|
||||
this can be simplified to:
|
||||
|
||||
.. code-block:: typoscript
|
||||
|
||||
page.20 = page-content
|
||||
|
||||
This however reduces the possibility to modify the select configuration
|
||||
(SQL statement), used to define which content should be fetched, as this
|
||||
is automatically handled by the data processor. However, there might be some
|
||||
use cases in which the result needs to be adjusted, e.g. to hide specific
|
||||
page content, like it's done by :ref:`EXT:content_blocks <friendsoftypo3/content-blocks:cb-nesting-prevent-output-fe>`
|
||||
for child elements. For such use cases, the new PSR-14 :php:`AfterContentHasBeenFetchedEvent`
|
||||
has been introduced, which allows to manipulate the list of fetched page
|
||||
content.
|
||||
|
||||
The following member properties of the event object are provided:
|
||||
|
||||
- :php:`$groupedContent`: The fetched page content, grouped by their column - as defined in the page layout
|
||||
- :php:`$request`: The current request, which can be used to e.g. access the page layout in question
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
The event listener class, using the PHP attribute :php:`#[AsEventListener]` for
|
||||
registration, removes some of the fetched page content elements based on
|
||||
specific field values.
|
||||
|
||||
.. code-block:: php
|
||||
:caption: my_extension/Classes/EventListener/MyEventListener.php
|
||||
|
||||
use TYPO3\CMS\Core\Attribute\AsEventListener;
|
||||
use TYPO3\CMS\Frontend\Event\AfterContentHasBeenFetchedEvent;
|
||||
|
||||
final class MyEventListener
|
||||
{
|
||||
#[AsEventListener]
|
||||
public function removeFetchedPageContent(AfterContentHasBeenFetchedEvent $event): void
|
||||
{
|
||||
foreach ($event->groupedContent as $columnIdentifier => $column) {
|
||||
foreach ($column['records'] ?? [] as $key => $record) {
|
||||
if ($record->has('parent_field_name') && (int)($record->get('parent_field_name') ?? 0) > 0) {
|
||||
unset($event->groupedContent[$columnIdentifier]['records'][$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Impact
|
||||
======
|
||||
|
||||
Using the new PSR-14 :php:`AfterContentHasBeenFetchedEvent`, it's possible
|
||||
to manipulate the page content, which has been fetched by the
|
||||
:php:`PageContentFetchingProcessor`, based on the page layout and
|
||||
corresponding columns configuration.
|
||||
|
||||
.. index:: Frontend, PHP-API, TypoScript, ext:frontend
|
||||
@@ -0,0 +1,72 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-103140-1708522119:
|
||||
|
||||
=============================================================================================
|
||||
Important: #103140 - Allow to configure rate limiters in Message consumer (Symfony Messenger)
|
||||
=============================================================================================
|
||||
|
||||
See :issue:`103140`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
This change introduces missing configuration options for Symfony Messenger-based
|
||||
rate limiters.
|
||||
|
||||
A **rate limiter** controls how frequently a specific event (e.g., HTTP request
|
||||
or login attempt) is allowed to occur. It acts as a safeguard to prevent services from
|
||||
being overwhelmed — either accidentally or intentionally — thus helping
|
||||
to maintain their availability.
|
||||
|
||||
Rate limiters are also useful for controlling internal or outbound
|
||||
processes, such as limiting the simultaneous processing of messages.
|
||||
|
||||
More information about the rate limiter is available in the
|
||||
`Symfony Rate Limiter component documentation
|
||||
<https://symfony.com/doc/current/rate_limiter.html>`__.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
Configure a rate limiter per queue
|
||||
----------------------------------
|
||||
|
||||
Rate limiters can be defined in your service configuration
|
||||
:file:`EXT:yourext/Configuration/Services.yaml`. The name specified
|
||||
in the settings is resolved to a service tagged with `messenger.rate_limiter`
|
||||
and the corresponding identifier.
|
||||
|
||||
Example Configuration:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: EXT:yourext/Configuration/Services.yaml
|
||||
:emphasize-lines: 10-12,23-25
|
||||
|
||||
messenger.rate_limiter.demo:
|
||||
class: 'Symfony\Component\RateLimiter\RateLimiterFactory'
|
||||
arguments:
|
||||
$config:
|
||||
id: 'demo'
|
||||
policy: 'sliding_window'
|
||||
limit: '100'
|
||||
interval: '60 seconds'
|
||||
$storage: '@Symfony\Component\RateLimiter\Storage\InMemoryStorage'
|
||||
tags:
|
||||
- name: 'messenger.rate_limiter'
|
||||
identifier: 'demo'
|
||||
|
||||
messenger.rate_limiter.default:
|
||||
class: 'Symfony\Component\RateLimiter\RateLimiterFactory'
|
||||
arguments:
|
||||
$config:
|
||||
id: 'default'
|
||||
policy: 'sliding_window'
|
||||
limit: '100'
|
||||
interval: '60 seconds'
|
||||
$storage: '@Symfony\Component\RateLimiter\Storage\InMemoryStorage'
|
||||
tags:
|
||||
- name: 'messenger.rate_limiter'
|
||||
identifier: 'default'
|
||||
|
||||
.. index:: PHP-API, ext:core
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-104477-1722069728:
|
||||
|
||||
=========================================================================
|
||||
Important: #104477 - Remove hyphen prefix from sys_log's data field entry
|
||||
=========================================================================
|
||||
|
||||
See :issue:`104477`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
The :php:`\TYPO3\CMS\Core\Log\Writer\DatabaseWriter` is used to write logs into
|
||||
the database table `sys_log`. Additional log information data is persisted
|
||||
in the field `data` and has been prefixed with a `-` until now.
|
||||
As this makes it harder to parse the data, which is JSON-encoded anyway,
|
||||
the prefix has been removed.
|
||||
|
||||
Beware that existing log entries are not migrated automatically.
|
||||
This leads to a mixed structure in the database table until old records are cleaned.
|
||||
(TYPO3 itself does not interpret the content of the field.)
|
||||
|
||||
.. index:: Database, ext:core
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-105007-1728977233:
|
||||
|
||||
=============================================================================
|
||||
Important: #105007 - Manipulation of final search query in EXT:indexed_search
|
||||
=============================================================================
|
||||
|
||||
See :issue:`105007`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
By removing the :typoscript:`searchSkipExtendToSubpagesChecking` option in
|
||||
:issue:`97530`, there might have been performance implications for installations
|
||||
with a lot of sites. This could be circumvented by adjusting the search query
|
||||
manually, using available hooks. Since those hooks have also been removed with
|
||||
:issue:`102937`, developers were no longer be able to handle the query
|
||||
behaviour.
|
||||
|
||||
Therefore, the PSR-14 :php:`BeforeFinalSearchQueryIsExecutedEvent` has been
|
||||
introduced which allows developers to manipulate the :php:`QueryBuilder`
|
||||
instance again, just before the query gets executed.
|
||||
|
||||
Additional context information, provided by the new event:
|
||||
|
||||
* :php:`searchWords` - The corresponding search words list
|
||||
* :php:`freeIndexUid` - Pointer to which indexing configuration should be searched in.
|
||||
-1 means no filtering. 0 means only regular indexed content.
|
||||
|
||||
.. important::
|
||||
|
||||
The provided query (the :php:`QueryBuilder` instance) is controlled by
|
||||
TYPO3 and is not considered public API. Therefore, developers using this
|
||||
event need to keep track of underlying changes by TYPO3. Such changes might
|
||||
be further performance improvements to the query or changes to the
|
||||
database schema in general.
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace MyVendor\MyExtension\EventListener;
|
||||
|
||||
use TYPO3\CMS\Core\Attribute\AsEventListener;
|
||||
use TYPO3\CMS\IndexedSearch\Event\BeforeFinalSearchQueryIsExecutedEvent;
|
||||
|
||||
final readonly class EventListener
|
||||
{
|
||||
#[AsEventListener(identifier: 'manipulate-search-query')]
|
||||
public function beforeFinalSearchQueryIsExecuted(BeforeFinalSearchQueryIsExecutedEvent $event): void
|
||||
{
|
||||
$event->queryBuilder->andWhere(
|
||||
$event->queryBuilder->expr()->eq('some_column', 'some_value')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
.. index:: PHP-API, ext:indexed_search
|
||||
+353
@@ -0,0 +1,353 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-105310-1736154830:
|
||||
|
||||
===================================================================
|
||||
Important: #105310 - Create CHAR and BINARY as fixed-length columns
|
||||
===================================================================
|
||||
|
||||
See :issue:`105310`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
TYPO3 parses `ext_tables.sql` files into a Doctrine DBAL object schema to define
|
||||
a virtual database scheme, enriched with :php:`DefaultTcaSchema` information for
|
||||
TCA-managed tables and fields.
|
||||
|
||||
Fixed and variable length variants have been parsed already in the past, but missed
|
||||
to flag the column as :php:`$fixed = true` for the fixed-length database field types
|
||||
:sql:`CHAR` and :sql:`BINARY`. This resulted in the wrong creation of these columns as
|
||||
:sql:`VARCHAR` and :sql:`VARBINARY`, which is now corrected.
|
||||
|
||||
+----------------+---------------------+------------------+
|
||||
| ext_tables.sql | created as (before) | created as (now) |
|
||||
+================+=====================+==================+
|
||||
| CHAR(10) | VARCHAR(10) | CHAR(10) |
|
||||
+----------------+---------------------+------------------+
|
||||
| VARCHAR(10) | VARCHAR(10) | VARCHAR(10) |
|
||||
+----------------+---------------------+------------------+
|
||||
| BINARY(10) | VARBINARY(10) | BINARY(10) |
|
||||
+----------------+---------------------+------------------+
|
||||
| VARBINARY(10) | VARBINARY(10) | VARBINARY(10) |
|
||||
+----------------+---------------------+------------------+
|
||||
|
||||
Not all database systems (RDBMS) act the same way for fixed-length columns. Implementation
|
||||
differences need to be respected to ensure the same query/data behaviour across all supported
|
||||
database systems.
|
||||
|
||||
.. warning::
|
||||
|
||||
Using fixed-length :sql:`CHAR` and :sql:`BINARY` column types requires to carefully work
|
||||
with data being persisted and retrieved from the database due to differently
|
||||
behaviour specifically of PostgreSQL.
|
||||
|
||||
|
||||
Fixed-length :sql:`CHAR`
|
||||
------------------------
|
||||
|
||||
**Key Difference Between CHAR and VARCHAR**
|
||||
|
||||
The main difference between :sql:`CHAR` and :sql:`VARCHAR` is how the database
|
||||
stores character data in a database. :sql:`CHAR`, which stands for `character`,
|
||||
is a fixed-length data type, meaning it always reserves a specific amount of
|
||||
storage space for each value, regardless of whether the actual data occupies
|
||||
that space entirely. For example, if a column is defined as :sql:`CHAR(10)` and
|
||||
the word `apple` is stored inside of it, it will still occupy 10 characters worth of
|
||||
space (not just 5). Unusued characters are padded with extra spaces.
|
||||
|
||||
On the other hand, :sql:`VARCHAR`, short for `variable character`, is a
|
||||
variable-length data type. It only uses as much storage space as needed
|
||||
to store the actual data without padding. So, storing the word `apple` in a
|
||||
:sql:`VARCHAR(10)` column will only occupy 5 characters worth of
|
||||
space, leaving the remaining table row space available for other data.
|
||||
|
||||
The main difference from `PostgreSQL` to `MySQL`/`MariaDB`/`SQLite` is:
|
||||
`PostgreSQL` also returns the filler-spaces for a value not having the
|
||||
column length (returning `apple[space][space][space][space][space]`).
|
||||
|
||||
On top of that, the filled-up spaces are also respected for query conditions, sorting
|
||||
or data calculations (:sql:`concat()` for example). These two facts makes a huge
|
||||
difference and **must** be carefully taken into account when using :sql:`CHAR`
|
||||
field.
|
||||
|
||||
**Rule of thumb for fixed-length** :sql:`CHAR` **columns**
|
||||
|
||||
* Only use with **ensured fixed-length values** (so that no padding occurs).
|
||||
|
||||
* For 255 or more characters :sql:`VARCHAR` or :sql:`TEXT` must be used.
|
||||
|
||||
**More hints for fixed-length** :sql:`CHAR` **columns**
|
||||
|
||||
* Ensure to write fixed-length values for :sql:`CHAR` (non-space characters),
|
||||
for example use hash algorithms which produce fixed-length hash identifier
|
||||
values.
|
||||
|
||||
* Ensure to use query statements to `trim` OR `rightPad` the value within
|
||||
:sql:`WHERE`, :sql:`HAVING` or :sql:`SELECT` operations, when values are
|
||||
not guaranteed to contain fixed-length values.
|
||||
|
||||
.. tip::
|
||||
|
||||
Helper :php:`\TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder`
|
||||
expressions can be used, for example
|
||||
:php-short:`\TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder->trim()` or
|
||||
:php-short:`\TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder->rightPad()` to.
|
||||
|
||||
* Usage of :sql:`CHAR` **must** be avoided when using the column with the
|
||||
`Extbase ORM`, because fixed-value length cannot be ensured due to the
|
||||
lack of using `trim/rightPad` within the ORM generated queries. Only with ensured
|
||||
fixed-length values, it is usable with `Extbase ORM`.
|
||||
|
||||
* Cover custom queries extensively with `functional tests` executed against
|
||||
all supported database platforms. Code within public extensions **should** ensure to test
|
||||
queries and their operations against all officially TYPO3-supported database platforms.
|
||||
|
||||
|
||||
Example of difference in behaviour of fixed-length :sql:`CHAR` types
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: sql
|
||||
:caption: Example ext_tables.sql defining a fixed-length tt_content field
|
||||
|
||||
CREATE TABLE `tt_content` (
|
||||
`some_label` CHAR(10) DEFAULT '' NOT NULL,
|
||||
);
|
||||
|
||||
Now, add some data. One row which fits exactly to 10 characters, and one row that only uses
|
||||
6 characters:
|
||||
|
||||
.. code-block:: php
|
||||
:caption: Adding two example rows
|
||||
:emphasize-lines: 12,22
|
||||
|
||||
<?php
|
||||
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getConnectionForTable('tt_content');
|
||||
// adding a value with 10 chars
|
||||
$queryBuilder->insert(
|
||||
'tt_content',
|
||||
[
|
||||
'some_label' => 'some-label',
|
||||
],
|
||||
[
|
||||
'some_label' => Connection::PARAM_STR,
|
||||
],
|
||||
);
|
||||
// adding a value with only 6 chars
|
||||
$queryBuilder->insert(
|
||||
'tt_content',
|
||||
[
|
||||
'some_label' => 'label1',
|
||||
],
|
||||
[
|
||||
'some_label' => Connection::PARAM_STR,
|
||||
],
|
||||
);
|
||||
|
||||
Now see the difference in retrieving these records:
|
||||
|
||||
.. code-block:: php
|
||||
:caption: Get all records from table
|
||||
|
||||
<?php
|
||||
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable('tt_content');
|
||||
$rows = $queryBuilder
|
||||
->select('uid', 'some_label')
|
||||
->from('tt_content')
|
||||
->executeQuery()
|
||||
->fetchAllAssociative();
|
||||
|
||||
Depending on the used database platform, the retrieved rows would contain these strings:
|
||||
|
||||
.. code-block:: php
|
||||
:caption: Result rows MySQL, MariaDB or SQLite
|
||||
:emphasize-lines: 6,10
|
||||
|
||||
<?php
|
||||
|
||||
$rows = [
|
||||
[
|
||||
'uid' => 1,
|
||||
'some_label' => 'some-label',
|
||||
],
|
||||
[
|
||||
'uid' => 2,
|
||||
'some_label' => 'label1',
|
||||
],
|
||||
];
|
||||
|
||||
but for PostgreSQL
|
||||
|
||||
.. code-block:: php
|
||||
:caption: Result rows with PostgreSQL
|
||||
:emphasize-lines: 6,12
|
||||
|
||||
<?php
|
||||
|
||||
$rows = [
|
||||
[
|
||||
'uid' => 1,
|
||||
'some_label' => 'some-label',
|
||||
],
|
||||
[
|
||||
'uid' => 2,
|
||||
// PostgreSQL applies the fixed length to the value directly,
|
||||
// filling it up with spaces
|
||||
'some_label' => 'label1 ',
|
||||
],
|
||||
];
|
||||
|
||||
or as a `diff` to make this even more visible:
|
||||
|
||||
.. code-block:: diff
|
||||
:caption: Result rows difference between database platforms (commented)
|
||||
|
||||
<?php
|
||||
|
||||
$rows = [
|
||||
[
|
||||
'uid' => 1,
|
||||
'some_label' => 'some-label',
|
||||
],
|
||||
[
|
||||
'uid' => 2,
|
||||
- 'some_label' => 'label1', // MySQL, MariaDB, SQLite
|
||||
+ 'some_label' => 'label1 ', // PostgreSQL
|
||||
],
|
||||
];
|
||||
|
||||
.. note::
|
||||
|
||||
Because of this, retrieved values need to be trimmed OR padded AFTER
|
||||
the query results are fetched, to ensure the same retrieved value across all
|
||||
supported database systems. Another option is to ensure that the persisted
|
||||
data always has a fixed-value length, like by using the aforementioned hashing
|
||||
algorithms (making results not human-readable).
|
||||
|
||||
To raise the awareness for problems on this topic, using the trimmed value inside
|
||||
a :sql:`WHERE` condition will match the record, but the returned value will be different
|
||||
from the value used in the condition:
|
||||
|
||||
.. code-block:: php
|
||||
:caption: Retrieve with trimmed value
|
||||
:emphasize-lines: 14,21,22
|
||||
|
||||
<?php
|
||||
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable('tt_content');
|
||||
$rows = $queryBuilder
|
||||
->select('uid', 'some_label')
|
||||
->from('tt_content')
|
||||
->where(
|
||||
$queryBuilder->eq(
|
||||
'some_label',
|
||||
$queryBuilder->createNamedParameter('label1'), // trimmed value!
|
||||
),
|
||||
)
|
||||
->executeQuery()
|
||||
->fetchAllAssociative();
|
||||
|
||||
// $rows contains the record for
|
||||
// PostgreSQL: $rows = [['uid' => 2, 'some_label' => 'label1 ']];
|
||||
// Others....: $rows = [['uid' => 2, 'some_label' => 'label1']];
|
||||
|
||||
.. code-block:: php
|
||||
:caption: Retrieve with enforced trimmed value.
|
||||
:emphasize-lines: 13-17,25,31,32,33
|
||||
|
||||
<?php
|
||||
|
||||
use Doctrine\DBAL\Platforms\TrimMode;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable('tt_content');
|
||||
$rows = $queryBuilder
|
||||
->select('uid')
|
||||
->addSelectLiteral(
|
||||
$queryBuilder->expr()->as(
|
||||
$queryBuilder->expr()->trim(
|
||||
'fixed_title',
|
||||
TrimMode::TRAILING,
|
||||
' '
|
||||
),
|
||||
'fixed_title',
|
||||
),
|
||||
)
|
||||
->from('tt_content')
|
||||
->where(
|
||||
$queryBuilder->eq(
|
||||
'some_label',
|
||||
$queryBuilder->createNamedParameter('label1'),
|
||||
),
|
||||
)
|
||||
->executeQuery()
|
||||
->fetchAllAssociative();
|
||||
|
||||
// $rows contains the record for
|
||||
// PostgreSQL: $rows = [['uid' => 2, 'some_label' => 'label1']];
|
||||
// Others....: $rows = [['uid' => 2, 'some_label' => 'label1']];
|
||||
// and ensures the same content across all supported database systems.
|
||||
|
||||
|
||||
On PostgreSQL, performing a query for a space-padded value will **not** actually
|
||||
return the expected row:
|
||||
|
||||
.. code-block:: php
|
||||
:caption: Retrieve with space-padded value for PostgreSQL does not retrieve the record
|
||||
:emphasize-lines: 16,22
|
||||
|
||||
<?php
|
||||
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
// PostgreSQL specific query!
|
||||
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable('tt_content');
|
||||
$rows = $queryBuilder
|
||||
->select('uid', 'some_label')
|
||||
->from('tt_content')
|
||||
->where(
|
||||
$queryBuilder->eq(
|
||||
'some_label',
|
||||
$queryBuilder->createNamedParameter('label1 '), // untrimmed value!
|
||||
),
|
||||
)
|
||||
->executeQuery()
|
||||
->fetchAllAssociative();
|
||||
|
||||
// $rows === []
|
||||
|
||||
Additional :php-short:`\TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder`
|
||||
methods can be used to ensure same behaviour on all platforms:
|
||||
|
||||
* :php-short:`\TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder::trim()`
|
||||
* :php-short:`\TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder::rightPad()`
|
||||
|
||||
Recommendation
|
||||
==============
|
||||
|
||||
:sql:`CHAR` and :sql:`BINARY` fields can be used (for storage or performance adjustments),
|
||||
but only when composed data and queries take care of database-system differences.
|
||||
|
||||
Otherwise, the "safe bet" is to consistently utilize :sql:`VARCHAR` and :sql:`VARBINARY`
|
||||
columns types.
|
||||
|
||||
.. index:: Database, ext:core
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-105653-1732210472:
|
||||
|
||||
=====================================================================================
|
||||
Important: #105653 - Require a template filename in extbase module template rendering
|
||||
=====================================================================================
|
||||
|
||||
See :issue:`105653`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
With the introduction of the FluidAdapter in TYPO3 v13, the dependency between
|
||||
Fluid and Extbase has been decoupled. As part of this change, the behavior of
|
||||
the :php:`ModuleTemplate::renderResponse()` and :php:`ModuleTemplate::render()`
|
||||
methods has been adjusted.
|
||||
|
||||
The :php:`$templateFileName` argument is now mandatory for the
|
||||
:php:`ModuleTemplate::renderResponse()` and :php:`ModuleTemplate::render()`
|
||||
methods. Previously, if this argument was not provided, the template was
|
||||
automatically resolved based on the controller and action names. Starting from
|
||||
TYPO3 13.4, calling these methods with an empty string or without a valid
|
||||
:php:`$templateFileName` will result in an :php:`InvalidArgumentException`.
|
||||
|
||||
Extensions using Extbase backend modules must explicitly provide the
|
||||
:php:`$templateFileName` when calling these methods. Existing implementations
|
||||
relying on automatic template resolution need to be updated to prevent
|
||||
runtime errors.
|
||||
|
||||
**Example**:
|
||||
|
||||
Before:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$moduleTemplate->renderResponse();
|
||||
|
||||
After:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$moduleTemplate->renderResponse('MyController/MyAction');
|
||||
|
||||
Note, that it is already possible to explicitly provide the
|
||||
:php:`$templateFileName` in TYPO3 12.4. It is therefore recommended to
|
||||
implement the new requirement for websites using TYPO3 12.4.
|
||||
|
||||
.. index:: Backend, ext:backend
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-105703-1742970227:
|
||||
|
||||
==========================================================================
|
||||
Important: #105703 - Premature end of script headers due to X-TYPO3-Cache-Tags
|
||||
==========================================================================
|
||||
|
||||
See :issue:`105703`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
The `X-TYPO3-Cache-Tags` header is now split into multiple lines if it exceeds the maximum
|
||||
of 8000 characters. This change prevents premature end of script headers and ensures
|
||||
that the header is sent correctly, even if it contains a large number of cache tags.
|
||||
|
||||
Affected installations
|
||||
----------------------
|
||||
|
||||
This change affects all TYPO3 installations that have `$GLOBALS['TYPO3_CONF_VARS']['FE']['debug']`
|
||||
enabled and misusing the `X-TYPO3-Cache-Tags` header for anything else then debugging.
|
||||
If you have a large number of cache tags, the header is now split into multiple
|
||||
lines to avoid exceeding the maximum header size limit imposed by some web servers.
|
||||
As this header is for debugging purposes only, this does not effect any production
|
||||
environments.
|
||||
|
||||
.. index:: Backend, ext:core
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-106401-1742479303:
|
||||
|
||||
============================================================================
|
||||
Important: #106401 - Treat 0 as a defined value for nullable datetime fields
|
||||
============================================================================
|
||||
|
||||
See :issue:`106401`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
For nullable integer-based datetime fields, the value `0` now explicitly
|
||||
represents the Unix epoch time (`1970-01-01T00:00:00Z`) instead of being
|
||||
interpreted as an empty value by FormEngine.
|
||||
|
||||
Only an explicit `null` database value will be considered an empty value.
|
||||
|
||||
The default database schema that is generated from TCA has been adapted
|
||||
to generate datetime columns with :sql:`DEFAULT NULL` instead of
|
||||
:sql:`DEFAULT 0` if they have been configured to be nullable.
|
||||
|
||||
Given the following TCA definition:
|
||||
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
'columns' => [
|
||||
'mydatefield' => [
|
||||
'config' => [
|
||||
'type' => 'datetime',
|
||||
'nullable' => true,
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
|
||||
The previously generated SQL statement will be changed from :sql:`DEFAULT 0` to
|
||||
:sql:`DEFAULT NULL`:
|
||||
|
||||
|
||||
.. code-block:: sql
|
||||
:caption: Nullable datetime schema before this change
|
||||
|
||||
`mydatefield` bigint(20) DEFAULT 0
|
||||
|
||||
|
||||
.. code-block:: sql
|
||||
:caption: Nullable datetime schema after this change
|
||||
|
||||
`mydatefield` bigint(20) DEFAULT NULL
|
||||
|
||||
|
||||
Fields that have not been explicitly configured to be nullable are unaffected
|
||||
and will default to `0` as before.
|
||||
|
||||
|
||||
.. index:: Backend, Database, JavaScript, ext:backend
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-106467-1743452295:
|
||||
|
||||
==================================================================================
|
||||
Important: #106467 - Align Extbase DateTime handling to FormEngine and DataHandler
|
||||
==================================================================================
|
||||
|
||||
See :issue:`106467`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
Extbase handling of :php:`\DateTimeInterface` domain model properties has been
|
||||
aligned with the persistence and database value interpretation behavior of the
|
||||
TYPO3 Core Engine (FormEngine and DataHandler).
|
||||
|
||||
Since this change addresses bugs and value interpretation differences that
|
||||
existed since the introduction of Extbase and there are many workarounds in use,
|
||||
a feature flag :php:`'extbase.consistentDateTimeHandling'` is introduced which
|
||||
allows to enable the new behavior.
|
||||
|
||||
Existing TYPO3 v13 instances will use the old behavior by default and are
|
||||
advised to enable the new feature flag via InstallTool or via:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SYS']['features']['extbase.consistentDateTimeHandling'] = true;
|
||||
|
||||
TYPO3 v14 (and new v13 instances) enable the consistent DateTime handling
|
||||
by default, but the feature can still be disabled manually, if needed for the
|
||||
time being.
|
||||
|
||||
There are four different behavioural changes that will be activated and are
|
||||
explained in the following sections.
|
||||
|
||||
|
||||
Align persistence to database to match DataHandler algorithm
|
||||
------------------------------------------------------------
|
||||
|
||||
Use the DataHandler algorithm for the mapping of DateTime objects
|
||||
to database values.
|
||||
This causes non-localtime timezone offsets in :php:`\DateTime` objects
|
||||
(e.g. supplied by a frontend datepicker) to be respected for native
|
||||
datetime fields, like already done for integer based datetime fields.
|
||||
Note that the offset is not stored as-is, but mapped to PHP localtime,
|
||||
but the offset is no longer cropped off.
|
||||
|
||||
That means there is no need to force the server timezone on :php:`\DateTime`
|
||||
objects before persisting an extbase model, since all dates will be
|
||||
normalized to localtime (for native datetime fields) or UTC (for integer based
|
||||
datetime fields) within the persistence layer.
|
||||
|
||||
Before:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function setDatetime(\DateTime $datetime): void
|
||||
{
|
||||
// Force local datetime zone in order to avoid
|
||||
// cropping non localtime offsets during persistence
|
||||
$datetime->setTimezone(
|
||||
new\DateTimeZone(date_default_timezone_get())
|
||||
);
|
||||
$this->datetime = $datetime;
|
||||
}
|
||||
|
||||
After:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function setDatetime(\DateTime $datetime): void
|
||||
{
|
||||
// No timezone enforcement needed, persistence layer will
|
||||
// persist correct point in time (UTC for integer, LOCALTIME for native
|
||||
// fields)
|
||||
$this->datetime = $datetime;
|
||||
}
|
||||
|
||||
|
||||
Map date and datetime with named timezone instead of offset
|
||||
-----------------------------------------------------------
|
||||
|
||||
Extbase DataMapper converts dates of integer based database fields to
|
||||
:php:`\DateTime` instances that use the current server date timezone
|
||||
(e.g., Europe/Berlin) and not just the time offset of the current server
|
||||
timezone (e.g., +01:00).
|
||||
|
||||
This prevents timezone shifts when modifying the resulting :php:`\DateTime`
|
||||
object across daylight saving time boundaries.
|
||||
|
||||
Previous workarounds that explicitly added the server timezone for properties
|
||||
can be removed:
|
||||
|
||||
Before:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function getDatetime(): ?\DateTime
|
||||
{
|
||||
// object(DateTimeZone)#1 (2) {
|
||||
// ["timezone_type"]=>
|
||||
// int(1)
|
||||
// ["timezone"]=>
|
||||
// string(6) "+01:00"
|
||||
// }
|
||||
var_dump($this->datetime);
|
||||
|
||||
$this->datetime->setTimezone(
|
||||
new\DateTimeZone(date_default_timezone_get())
|
||||
);
|
||||
|
||||
return $this->datetime;
|
||||
}
|
||||
|
||||
After:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function getDatetime(): ?\DateTime
|
||||
{
|
||||
// object(DateTimeZone)#2 (2) {
|
||||
// ["timezone_type"]=>
|
||||
// int(3)
|
||||
// ["timezone"]=>
|
||||
// string(13) "Europe/Berlin"
|
||||
// }
|
||||
var_dump($this->datetime);
|
||||
|
||||
// No explicit timezone needed for a proper named timezone
|
||||
return $this->datetime;
|
||||
}
|
||||
|
||||
|
||||
Interpret integer based time fields as seconds without timezone offset
|
||||
----------------------------------------------------------------------
|
||||
|
||||
The Extbase DataMapper will interpret `format=time` or `format=timesec`
|
||||
datetime fields as seconds without timezone offset, like FormEngine and
|
||||
DataHandler do. The database value is no longer considered as a UNIX timestamp,
|
||||
but as offset from midnight mapped on 1970-01-01T00:00:00 in PHP localtime.
|
||||
|
||||
For european timezones where Central Europe Time (CET) was active on 1970-01-01
|
||||
that means an integer field value like `7200` (=`02:00`) will be mapped to
|
||||
`1970-01-01T02:00:00+01:00` instead of `1970-01-01T02:00:00+00:00` and the
|
||||
:php:`DateTime::$timezone` property of the :php:`DateTime` object will be set to
|
||||
the named timezone that is configured in PHP ini setting `date.timezone` instead
|
||||
of UTC.
|
||||
|
||||
That means the datetime value can be combined with explicit dates and is always
|
||||
using the server timezone.
|
||||
|
||||
|
||||
Interpret 00:00:00 as non empty time value for nullable time properties
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
Nullable `format=time`, `format=timesec` or `dbType=time` fields can now
|
||||
use 00:00:00 to represent midnight (this value has been used in
|
||||
non-nullable fields to represent an empty value). The DateTime mapper now
|
||||
understands this value instead of misinterpreting it as an empty value.
|
||||
|
||||
This behaviour could not be worked around before, that means existing
|
||||
implementations do not need to change or remove workarounds, but can basically
|
||||
support 00:00 as a value time field now.
|
||||
|
||||
|
||||
Construct `format=time` and `dbType=time` properties based on 1970-01-01
|
||||
------------------------------------------------------------------------
|
||||
|
||||
DateTime objects that map to native TIME fields or integer based fields
|
||||
configured with `format=time` are now initialized with 1970-01-01 as day-part
|
||||
instead of the current day which results in consistent mapped values independent
|
||||
from the day where the mapping is performed.
|
||||
|
||||
Before:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function getDatetime(): ?\DateTime
|
||||
{
|
||||
//object(DateTime)#2 (3) {
|
||||
// ["date"]=>
|
||||
// string(26) "2025-04-11 11:44:00.000000"
|
||||
// ["timezone_type"]=>
|
||||
// int(1)
|
||||
// ["timezone"]=>
|
||||
// string(6) "+02:00"
|
||||
//}
|
||||
|
||||
var_dump($this->datetime);
|
||||
|
||||
return $this->datetime;
|
||||
}
|
||||
|
||||
After:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function getDatetime(): ?\DateTime
|
||||
{
|
||||
//object(DateTime)#2 (3) {
|
||||
// ["date"]=>
|
||||
// string(26) "1970-01-01 11:44:00.000000"
|
||||
// ["timezone_type"]=>
|
||||
// int(3)
|
||||
// ["timezone"]=>
|
||||
// string(13) "Europe/Berlin"
|
||||
//}
|
||||
var_dump($this->datetime);
|
||||
|
||||
return $this->datetime;
|
||||
}
|
||||
|
||||
|
||||
.. index:: Database, PHP-API, ext:extbase
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-106494-1744372580:
|
||||
|
||||
=============================================================================================================================================
|
||||
Important: #106494 - Adapt custom instances of AbstractFormFieldViewHelper to deal with `persistenceManager->getIdentifierByObject()` methods
|
||||
=============================================================================================================================================
|
||||
|
||||
See :issue:`106494`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
When dealing with relations to multilingual Extbase entities, these relations should always store
|
||||
their reference to the "original" (`sys_language_uid=0`) entity, so that later on,
|
||||
language record overlays can be properly applied.
|
||||
|
||||
For this to work in areas like persistence, internally an "identifier" is established that references
|
||||
these multilingual objects like `[defaultLanguageRecordUid]_[localizedRecordUid]`.
|
||||
|
||||
Internally, this identifier should be converted back to only contain/reference the `defaultLanguageRecordUid`.
|
||||
|
||||
A bug has been fixed with #106494 to deal with this inside the `<f:form.select>` ViewHelper, which utilized
|
||||
an `<option value="11_42">` (defaultLanguageRecordUid=11, localizedRecordUid=42), and when using an `<f:form>`
|
||||
to edit existing records, the currently attached records would NOT get pre-selected.
|
||||
|
||||
When such objects with relations were persisted (in frontend management interfaces with Extbase), if the proper
|
||||
option had not been selected again, the relation would get lost.
|
||||
|
||||
Important: Adapt custom ViewHelpers extended from AbstractFormFieldViewHelper or using persistenceManager->getIdentifierByObject()
|
||||
----------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
The bug has been fixed, but it is important that if third-party code created custom ViewHelpers based on
|
||||
:php:`TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormFieldViewHelper`, these may need adoption too.
|
||||
|
||||
Instead of using code like this:
|
||||
|
||||
.. code-block:: php
|
||||
:caption: Example ViewHelper code utilizing persistenceManager->getIdentifierByObject()
|
||||
|
||||
if ($this->persistenceManager->getIdentifierByObject($valueElement) !== null) {
|
||||
return $this->persistenceManager->getIdentifierByObject($valueElement);
|
||||
}
|
||||
|
||||
the code should be adopted to not rely on `getIdentifierByObject()` but instead:
|
||||
|
||||
.. code-block:: php
|
||||
:caption: Refactored ViewHelper code preferring an object's getUid() method instead
|
||||
|
||||
if ($this->persistenceManager->getIdentifierByObject($valueElement) !== null) {
|
||||
if ($valueElement instanceof DomainObjectInterface) {
|
||||
return $valueElement->getUid() ?? $this->persistenceManager->getIdentifierByObject($valueElement);
|
||||
}
|
||||
return $this->persistenceManager->getIdentifierByObject($valueElement);
|
||||
}
|
||||
|
||||
This code ensures that retrieving the relational object's UID is done with the overlaid record,
|
||||
and only falls back to the full identifier, if it's not set, or not an object implementing the Extbase
|
||||
DomainObjectInterface.
|
||||
|
||||
Also note that the abstract's method :php:`convertToPlainValue()` has been fixed to no longer return
|
||||
a value of format `[defaultLanguageRecordUid]_[localizedRecordUid]` but instead always use the
|
||||
original record's `->getUid()` return value (=`defaultLanguageRecordUid`).
|
||||
|
||||
If this method :php:`convertToPlainValue()` is used in 3rd-party code, make sure this is the
|
||||
expected result, too.
|
||||
|
||||
|
||||
.. index:: Fluid, Frontend, PHP-API, ext:extbase
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-106508-1743692685:
|
||||
|
||||
=====================================================================================
|
||||
Important: #106508 - Respect column `CHARACTER SET` and `COLLATE` in `ext_tables.sql`
|
||||
=====================================================================================
|
||||
|
||||
See :issue:`106508`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
TYPO3 now reads column based `CHARACTER SET` and `COLLATION` from extension
|
||||
:file:`ext_tables.sql` files and applies them on column level. This allows
|
||||
`CHARACTER SET` and `COLLATION` column settings different than defaults defined
|
||||
on table or schema level. This is limited to `MySQL` and `MariaDB` DBMS.
|
||||
|
||||
.. note::
|
||||
|
||||
Setting different charset and collation comes with some technical impact
|
||||
during query time and requires for some queries special handling, for instance
|
||||
when joining field that have different charsets or collations. Setting special
|
||||
charsets and collations for single columns should only be used in rare
|
||||
cases. The support is `@internal` and should be used with care if at all.
|
||||
|
||||
|
||||
For now, :sql:`CHARACTER SET ascii COLLATE ascii_bin` is used for
|
||||
:sql:`sys_refindex.hash` to reduce required space for the index using
|
||||
single bytes instead of multiple bytes per character.
|
||||
|
||||
The introduced database change is considerable non-breaking, because:
|
||||
|
||||
* Not applying the database changes still keeps a fully working state.
|
||||
* Applying database schema change does not require data migrations.
|
||||
* Targets only `MySQL` and `MariaDB`.
|
||||
|
||||
.. code-block:: sql
|
||||
:caption: ext_tables.sql example
|
||||
|
||||
CREATE TABLE some_table (
|
||||
|
||||
col1 CHAR(10) DEFAULT '' NOT NULL CHARACTER SET ascii COLLATE ascii_bin,
|
||||
col2 CHAR(10) CHARACTER SET ascii COLLATE ascii_bin DEFAULT '' NOT NULL,
|
||||
col3 VARCHAR(10) DEFAULT '' NOT NULL CHARACTER SET ascii COLLATE ascii_bin,
|
||||
col4 VARCHAR(10) CHARACTER SET ascii COLLATE ascii_bin DEFAULT '' NOT NULL,
|
||||
col5 TEXT DEFAULT '' NOT NULL CHARACTER SET ascii COLLATE ascii_bin,
|
||||
col6 TEXT CHARACTER SET ascii COLLATE ascii_bin DEFAULT '' NOT NULL,
|
||||
col7 MEDIUMTEXT DEFAULT '' NOT NULL CHARACTER SET ascii COLLATE ascii_bin,
|
||||
col8 MEDIUMTEXT CHARACTER SET ascii COLLATE ascii_bin DEFAULT '' NOT NULL,
|
||||
col9 LONGTEXT DEFAULT '' NOT NULL CHARACTER SET ascii COLLATE ascii_bin,
|
||||
col10 LONGTEXT CHARACTER SET ascii COLLATE ascii_bin DEFAULT '' NOT NULL,
|
||||
);
|
||||
|
||||
.. index:: Database, ext:core
|
||||
@@ -0,0 +1,75 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-106894-1750144877:
|
||||
|
||||
==============================================================
|
||||
Important: #106894 - Site settings.yaml is now stored as a map
|
||||
==============================================================
|
||||
|
||||
See :issue:`106894`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
Site settings are defined as a map of keys, with a defined
|
||||
type and default.
|
||||
|
||||
The values were previously stored as a tree representation in
|
||||
:file:`settings.yaml`, e.g.:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: EXT:my_extension/Configuration/Sets/MySet/settings.yaml
|
||||
|
||||
foo:
|
||||
bar: 'value'
|
||||
|
||||
This tree representation is easier to write, but has the
|
||||
drawback that arbitrary keys like `foo.bar` and `foo.bar.baz`
|
||||
exclude each other, as the subkey `baz` would be represented
|
||||
as a value of `foo.bar` in tree representation.
|
||||
|
||||
Note that TypoScript constants can express subkey constants since
|
||||
TypoScript can store a value and childnodes for every node, which
|
||||
means that existing extensions – that migrate to site sets – require
|
||||
this mixture of setting identifiers to be supported in order to
|
||||
avoid breaking existing settings.
|
||||
|
||||
The storage format of settings.yaml is now changed to use
|
||||
a map (like settings.definitions.yaml already do) to store
|
||||
setting values, in order to overcome the mentioned limitation.
|
||||
It is still supported to *read* from a tree, but the settings editor
|
||||
will convert the tree to a map when persisting values.
|
||||
|
||||
Given the following setting definition:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: EXT:my_extension/Configuration/Sets/MySet/settings.definitions.yaml
|
||||
|
||||
settings:
|
||||
foo.bar:
|
||||
type: string
|
||||
default: ''
|
||||
label: FooBar
|
||||
foo.bar.baz:
|
||||
type: string
|
||||
default: ''
|
||||
label: FooBarBaz
|
||||
|
||||
|
||||
A map will be stored in :file:`settings.yaml` that is able to store values for
|
||||
both setting identifiers:
|
||||
|
||||
.. code-block:: yaml
|
||||
:caption: typo3conf/sites/mysite/settings.yaml
|
||||
|
||||
foo.bar: 'Foo bar value'
|
||||
foo.bar.baz: 'Foo Bar baz value'
|
||||
|
||||
Also site sets are advised to use this format for settings provided in their sets
|
||||
:file:`settings.yaml` file.
|
||||
|
||||
Existing anonymous settings (pre v13 style, e.g. settings without a
|
||||
matching settings.definitions.yaml definition) will be preserved as
|
||||
a tree, since it is not known which tree node is key or a value.
|
||||
|
||||
.. index:: YAML, ext:core
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-107062-1759872067:
|
||||
|
||||
===========================================================================================
|
||||
Important: #107062 - Avoid applying Content-Security-Policy nonce sources when not required
|
||||
===========================================================================================
|
||||
|
||||
See :issue:`107062`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
Using nonce sources in a Content-Security-Policy (CSP) HTTP header implicitly leads
|
||||
to having a `Cache-Control: private, no-store` HTTP response header and internally
|
||||
requires to renew the nonce value that is present in cached HTML contents, which
|
||||
has a negative impact on performance.
|
||||
|
||||
This change aims for having fully cached pages and tries to avoid nonce sources
|
||||
in the CSP header when actually feasible.
|
||||
|
||||
* The :php:`ConsumableNonce` class was refactored – it no longer extends
|
||||
:php:`ConsumableString`.
|
||||
* Two new counters are introduced:
|
||||
:php:`consumeInline()` – the nonce is **required** for an inline resource.
|
||||
:php:`consumeStatic()` – the nonce is **optional** for a static resource.
|
||||
|
||||
Example usage:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
$nonce = new ConsumableNonce();
|
||||
$nonce->consumeInline(Directive::ScriptSrcElem); // inline script
|
||||
$nonce->consumeStatic(Directive::StyleSrcElem); // static style
|
||||
|
||||
Nonce sources are removed from the CSP policy in the following
|
||||
situations, in case the request is supposed to be fully cacheable
|
||||
(`config.no_cache = 0` and not having any `USER_INT` or `COA_INT` items):
|
||||
|
||||
* The response body is readable and contains **no** bytes.
|
||||
* The nonce consumption counter for **all** usages equals zero.
|
||||
* A directive contains a source‑keyword exception (e.g. `'unsafe-inline'`)
|
||||
that makes a nonce unnecessary.
|
||||
* The :php:`PolicyPreparedEvent` has been dispatched and explicitly tells
|
||||
the policy to avoid using nonce sources.
|
||||
|
||||
When the nonce should be removed, both the frontend and backend
|
||||
:php:`ContentSecurityPolicyHeaders` middleware strip the nonce-related
|
||||
literals from the rendered HTML.
|
||||
|
||||
New PSR-14 event
|
||||
----------------
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Example\MyPackage\EventListener;
|
||||
|
||||
use TYPO3\CMS\Core\Attribute\AsEventListener;
|
||||
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\Disposition;
|
||||
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\Event\PolicyPreparedEvent;
|
||||
|
||||
#[AsEventListener('my-package/content-security-policy/avoid-nonce')]
|
||||
final class DropNonceEventListener
|
||||
{
|
||||
public function __invoke(PolicyPreparedEvent $event): void
|
||||
{
|
||||
$policyBag = $event->policyBag;
|
||||
if (
|
||||
isset($policyBag->dispositionMap[Disposition::enforce])
|
||||
&& $policyBag->scope->siteIdentifier === 'my-special-site'
|
||||
// YOLO: drop nonce sources, even it is consumed
|
||||
&& $policyBag->nonce->count() > 0
|
||||
) {
|
||||
$policyBag->behavior->useNonce = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
New :php:`useNonce` property
|
||||
----------------------------
|
||||
|
||||
The :php:`\TYPO3\CMS\Core\Security\ContentSecurityPolicy\Configuration\Behavior`
|
||||
class now contains the nullable boolean property :php:`useNonce`:
|
||||
|
||||
* :php:`true` - explicitly allows using nonce sources
|
||||
* :php:`null` - the default unspecific state (the system will detect and decide automatically)
|
||||
* :php:`false` - explicitly denies using nonce sources, it also drops constraints like
|
||||
`'strict-dynamic'` since that source keyword requires a nonce source
|
||||
|
||||
.. index:: Backend, Frontend, PHP-API, ext:core
|
||||
@@ -0,0 +1,78 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-107063-1752056295:
|
||||
|
||||
===========================================================================
|
||||
Important: #107063 - CKEditor 5 v46.1.0: TypeScript imports and CSS changes
|
||||
===========================================================================
|
||||
|
||||
See :issue:`107063`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
With the upgrade to CKEditor 5 v46.1.0, three relevant changes are made:
|
||||
|
||||
#. The API naming of TypeScript type imports has changed a lot. Any custom
|
||||
CKEditor 5 plugin using TypeScript type imports in their build chain will
|
||||
need to be adapted to match these imports.
|
||||
See `https://ckeditor.com/docs/ckeditor5/latest/updating/nim-migration/migrating-imports.html`_
|
||||
for a large table of "before->after" renames.
|
||||
This is not considered a breaking change in context of TYPO3 integration,
|
||||
because existing JavaScript modules will continue to work, as TypeScript
|
||||
type imports are not part of the final output. Runtime imports that are
|
||||
exposed by the `@ckeditor5/ckeditor-*` modules have not been changed
|
||||
and will continue to work.
|
||||
|
||||
#. A new opinionated default CSS is used by CKEditor to apply some
|
||||
improved styling over contents displayed within the RTE interface.
|
||||
Most of these are overruled by TYPO3's default CSS integration though.
|
||||
Possible customizations need to respect this.
|
||||
|
||||
#. A few CSS classes have been renamed, see
|
||||
`https://ckeditor.com/docs/ckeditor5/latest/updating/guides/update-to-46.html`_.
|
||||
These are for example referenced in custom CKEditor YAML configurations like
|
||||
the following diff, and need to replace the `color` subkey:
|
||||
|
||||
.. code-block:: diff
|
||||
:caption: Configuration/RTE/Full.yaml - Before/After
|
||||
|
||||
- {
|
||||
model: 'yellowMarker',
|
||||
class: 'marker-yellow',
|
||||
title: 'Yellow marker',
|
||||
type: 'marker',
|
||||
- color: 'var(--ck-highlight-marker-yellow)'
|
||||
+ color: 'var(--ck-content--highlight-marker-yellow)'
|
||||
}
|
||||
- {
|
||||
model: 'greenMarker',
|
||||
class: 'marker-green',
|
||||
title: 'Green marker',
|
||||
type: 'marker',
|
||||
- color: 'var(--ck-highlight-marker-green)'
|
||||
+ color: 'var(--ck-content-highlight-marker-green)'
|
||||
}
|
||||
- {
|
||||
model: 'redPen',
|
||||
class: 'pen-red',
|
||||
title: 'Red pen',
|
||||
type: 'pen',
|
||||
- color: 'var(--ck-highlight-pen-red)'
|
||||
+ color: 'var(--ck-content-highlight-pen-red)'
|
||||
}
|
||||
|
||||
|
||||
Affected installations
|
||||
======================
|
||||
|
||||
TYPO3 installation relying on custom or third-party CKEditor 5 TypeScript build chains,
|
||||
or CSS adaptations that no longer match the CKEditor 5 naming.
|
||||
|
||||
|
||||
Possible Migration
|
||||
==================
|
||||
|
||||
Follow the CKEditor 5 upgrade guide to change CSS class names and TypeScript imports.
|
||||
|
||||
.. index:: Backend, RTE, NotScanned
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-107342-1761324027:
|
||||
|
||||
===============================================================================
|
||||
Important: #107342 - Extend listForms method in FormPersistenceManagerInterface
|
||||
===============================================================================
|
||||
|
||||
See :issue:`107342`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
With this change, the method signature of :php:`listForms()`, defined by the :php:`FormPersistenceManagerInterface`,
|
||||
has been extended by two arguments: :php:`$orderField` and :php:`$orderDirection`.
|
||||
The new definition is:
|
||||
:php:`public function listForms(array $formSettings, string $orderField = '', ?SortDirection $orderDirection = null): array;`
|
||||
|
||||
|
||||
Affected Installations
|
||||
======================
|
||||
|
||||
Some TYPO3 installations may use this interface for their own FormPersistenceManager, even though it is marked as internal.
|
||||
|
||||
|
||||
Possible Migration
|
||||
==================
|
||||
|
||||
If you have implemented your own FormPersistenceManager, you need to update the method signature accordingly.
|
||||
|
||||
.. index:: Backend, ext:form, NotScanned
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-107594-1759439282:
|
||||
|
||||
======================================================
|
||||
Important: #107594 - Icon overlay for TCA select items
|
||||
======================================================
|
||||
|
||||
See :issue:`107594`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
The ability to define an icon overlay for items in the "New Content Element"
|
||||
wizard was originally introduced in :issue:`92942` using Page TSconfig, but was
|
||||
accidentally removed during the web-component migration in :issue:`100065` and
|
||||
then restored in :issue:`105253`.
|
||||
|
||||
In the meantime, :issue:`102834` added auto-registration of wizard items
|
||||
directly from TCA. Since icon overlays defined in Page TSconfig duplicate
|
||||
configuration that can now be specified in TCA, the recommended approach is to
|
||||
define icon overlays directly in TCA using the new :php:`iconOverlay` option
|
||||
for select items.
|
||||
|
||||
The :php:`iconOverlay` property is now supported in the :php:`SelectItem`
|
||||
component, enabling icon overlays for wizard items that are auto-registered
|
||||
via TCA.
|
||||
|
||||
Impact
|
||||
======
|
||||
|
||||
Icon overlays for New Content Element Wizard items can now be defined directly
|
||||
in TCA alongside other item properties like :php:`icon`, :php:`label`,
|
||||
:php:`description`, and :php:`group`.
|
||||
|
||||
This consolidates configuration in a single location and eliminates the need
|
||||
for separate Page TSconfig definitions. Page TSconfig icon overlays remain
|
||||
supported for backward compatibility, but TCA-based configuration is now the
|
||||
recommended approach.
|
||||
|
||||
Migration
|
||||
=========
|
||||
|
||||
**Previous approach using Page TSconfig (still works, but no longer recommended):**
|
||||
|
||||
.. code-block:: typoscript
|
||||
:caption: EXT:my_extension/Configuration/page.tsconfig
|
||||
|
||||
mod.wizards.newContentElement.wizardItems {
|
||||
my_group.elements {
|
||||
my_element {
|
||||
iconIdentifier = content-header
|
||||
iconOverlay = actions-approve
|
||||
title = LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:my_element_title
|
||||
description = LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:my_element_description
|
||||
tt_content_defValues {
|
||||
CType = my_element
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
**Recommended approach using TCA:**
|
||||
|
||||
.. code-block:: php
|
||||
:caption: EXT:my_extension/Configuration/TCA/Overrides/tt_content.php
|
||||
|
||||
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
|
||||
|
||||
ExtensionManagementUtility::addRecordType(
|
||||
[
|
||||
'label' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:my_element_title',
|
||||
'description' => 'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:my_element_description',
|
||||
'value' => 'my_element',
|
||||
'icon' => 'content-header',
|
||||
'iconOverlay' => 'actions-approve',
|
||||
'group' => 'my_group'
|
||||
],
|
||||
'...',
|
||||
);
|
||||
|
||||
.. important::
|
||||
|
||||
While Page TSconfig-based icon overlay configuration remains functional for
|
||||
backward compatibility, it is recommended to migrate to TCA-based
|
||||
configuration to avoid duplicating configuration across multiple files.
|
||||
|
||||
.. index:: Backend, TCA, TSConfig, ext:backend
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-107649-1760090777:
|
||||
|
||||
============================================================================
|
||||
Important: #107649 - Dependency Injection cache is now PHP version dependant
|
||||
============================================================================
|
||||
|
||||
See :issue:`107649`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
TYPO3 uses the PHP library `symfony/dependency-injection` to build a dependency
|
||||
injection container that contains class factories for services used by TYPO3 or
|
||||
by installed extensions.
|
||||
|
||||
With the update to `symfony/dependency-injection` v7.3 – which may be installed
|
||||
in TYPO3 v13 composer mode – the created factories are optimized to use certain
|
||||
PHP language level features, if available, which result in a cache that is
|
||||
incompatible when used with older PHP versions.
|
||||
|
||||
In a scenario where the dependency injection cache is created in a CLI PHP
|
||||
process (e.g. PHP v8.4), this may result in a cache to be created that is
|
||||
incompatible with a Web PHP process (e.g. PHP v8.2), if the minor versions
|
||||
of the CLI and Web environments differ.
|
||||
|
||||
For this reason the major and minor PHP version numbers are now hashed into the
|
||||
dependency injection cache identifier, resulting in a possible cache-miss on the
|
||||
first web-request after a deployment, if the system was prepared via
|
||||
:bash:`bin/typo3` with a CLI PHP process version that is different to the Web
|
||||
PHP version.
|
||||
|
||||
Make sure to configure the PHP CLI process version :bash:`php -v` to use
|
||||
the same version number as configured for the Web process. The Web process
|
||||
version can be introspected in the backend toolbar entry
|
||||
:guilabel:`System Information > PHP Version`.
|
||||
|
||||
.. index:: CLI, ext:core
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-107681-1760427687:
|
||||
|
||||
=========================================================================
|
||||
Important: #107681 - Disabled state for ShortcutButton and DropDownButton
|
||||
=========================================================================
|
||||
|
||||
See :issue:`107681`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
The :php:`ShortcutButton` and :php:`DropDownButton` classes in the TYPO3
|
||||
backend button bar system have been enhanced with new methods to support
|
||||
disabled state functionality. This brings them in line with other button
|
||||
types that already support the disabled state.
|
||||
|
||||
Two new methods have been added to both classes:
|
||||
|
||||
- :php:`isDisabled(): bool` - Checks if the button is disabled
|
||||
- :php:`setDisabled(bool $disabled)` - Sets the disabled state of the button
|
||||
|
||||
When a button is disabled, it is rendered with appropriate HTML attributes
|
||||
and CSS classes to indicate its non-interactive state. For :php:`ShortcutButton`,
|
||||
the disabled state is applied to both the simple button rendering and the
|
||||
dropdown rendering modes.
|
||||
|
||||
Impact
|
||||
======
|
||||
|
||||
Extension developers can now programmatically disable shortcut and dropdown
|
||||
buttons in the TYPO3 backend, preventing user interaction when needed. This is
|
||||
particularly useful for:
|
||||
|
||||
- Preventing operations during form initialization
|
||||
- Disabling buttons during async operations
|
||||
- Conditional button availability based on application state
|
||||
- Improving user experience on slow network connections
|
||||
|
||||
The disabled state is properly propagated through the rendering process:
|
||||
|
||||
- For shortcut buttons rendered as :php:`GenericButton`, the disabled
|
||||
attribute is added to the button element
|
||||
- For shortcut buttons rendered as :php:`DropDownButton`, the disabled
|
||||
state is passed to the dropdown button
|
||||
|
||||
Migration
|
||||
=========
|
||||
|
||||
No migration is required. This change is fully backward compatible as it only
|
||||
adds new optional functionality. Existing code will continue to work without
|
||||
modifications.
|
||||
|
||||
**Example usage for disabling a shortcut button:**
|
||||
|
||||
.. code-block:: php
|
||||
:caption: EXT:my_extension/Classes/Controller/MyController.php
|
||||
|
||||
$shortcutButton = $buttonBar->makeShortcutButton()
|
||||
->setRouteIdentifier('my_module')
|
||||
->setDisplayName('My Module')
|
||||
->setArguments(['id' => $pageId])
|
||||
->setDisabled(true);
|
||||
$buttonBar->addButton($shortcutButton);
|
||||
|
||||
**Example usage for disabling a dropdown button:**
|
||||
|
||||
.. code-block:: php
|
||||
:caption: EXT:my_extension/Classes/Controller/MyController.php
|
||||
|
||||
$dropdownButton = GeneralUtility::makeInstance(DropDownButton::class)
|
||||
->setLabel('Actions')
|
||||
->setIcon($iconFactory->getIcon('actions-menu'))
|
||||
->setDisabled(true);
|
||||
$dropdownButton->addItem($item1);
|
||||
$dropdownButton->addItem($item2);
|
||||
$buttonBar->addButton($dropdownButton);
|
||||
|
||||
**Example usage for checking disabled state:**
|
||||
|
||||
.. code-block:: php
|
||||
:caption: EXT:my_extension/Classes/Controller/MyController.php
|
||||
|
||||
if ($shortcutButton->isDisabled()) {
|
||||
// Handle disabled state
|
||||
}
|
||||
|
||||
.. index:: Backend, PHP-API, ext:backend
|
||||
@@ -0,0 +1,120 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-108604-1780297491:
|
||||
|
||||
===================================================
|
||||
Important: #108604 - Mitigate deserialization flaws
|
||||
===================================================
|
||||
|
||||
See :issue:`108604`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
TYPO3 introduces new serialization infrastructure to protect against PHP object
|
||||
injection attacks. Two complementary strategies are applied depending on how
|
||||
long the serialized data lives:
|
||||
|
||||
**Cache frontend (**:php:`VariableFrontend`**) — HMAC-authenticated serialization**
|
||||
|
||||
:php:`\TYPO3\CMS\Core\Cache\Frontend\VariableFrontend` (the default cache
|
||||
frontend) now uses
|
||||
:php:`\TYPO3\CMS\Core\Serializer\AuthenticatedMessageDeserializer` for both
|
||||
writing and reading cache entries. On every :php:`set()` call the payload is
|
||||
serialized and an HMAC is appended; on every :php:`get()` call the HMAC is
|
||||
validated before deserialization proceeds.
|
||||
|
||||
Because caches are temporary and written exclusively by the server that reads
|
||||
them, this approach provides a strong integrity guarantee: an attacker cannot
|
||||
craft a malicious serialized payload that the server would accept, since they
|
||||
cannot forge the HMAC without knowing the encryption key.
|
||||
|
||||
Cache entries written by an older TYPO3 version (without an HMAC) are handled
|
||||
gracefully: if the payload contains no PHP class tokens it is deserialized
|
||||
safely with :php:`allowed_classes: false`; if it does contain class tokens it
|
||||
is discarded and treated as a cache miss, causing the entry to be regenerated
|
||||
transparently.
|
||||
|
||||
**Registry (**:php:`\TYPO3\CMS\Core\Registry`**) — gadget denylist**
|
||||
|
||||
:php:`\TYPO3\CMS\Core\Registry` (the persistent key-value store backed by the
|
||||
:sql:`sys_registry` table) deserializes stored payloads through
|
||||
:php:`\TYPO3\CMS\Core\Serializer\DenyListDeserializer`. Before deserialization
|
||||
the class names embedded in the payload are checked against a gadget deny list.
|
||||
The deny/allow decision for each class is resolved lazily via
|
||||
:php:`\ReflectionClass` on first encounter and then cached in :php:`cache:core`
|
||||
(HMAC-signed for integrity) so that reflection is not repeated for the same
|
||||
class within a cache lifetime. A class is considered a gadget when it carries a
|
||||
user-defined :php:`__destruct()` or an exploitable :php:`__wakeup()` — that is,
|
||||
a :php:`__wakeup()` not provided solely by
|
||||
:php:`\TYPO3\CMS\Core\Security\BlockSerializationTrait`. If any gadget class is
|
||||
referenced in a payload, a
|
||||
:php:`\TYPO3\CMS\Core\Serializer\Exception\DeserializerException` is thrown and
|
||||
deserialization is aborted.
|
||||
|
||||
A denylist strategy (block known-bad, allow unknown) is used intentionally for
|
||||
the registry to avoid breaking changes to long-lived persisted data.
|
||||
|
||||
Impact
|
||||
------
|
||||
|
||||
**Cache (**:php:`VariableFrontend`**)**
|
||||
|
||||
Existing cache entries that contain serialized PHP objects will be treated as
|
||||
cache misses on the next read. No exception is thrown; the entry is simply
|
||||
discarded and the cache is repopulated on the next request. This is transparent
|
||||
to callers.
|
||||
|
||||
**Registry**
|
||||
|
||||
Extensions or third-party code that stores serialized PHP objects in
|
||||
:php:`Registry` may encounter a :php:`DeserializerException` at read time if
|
||||
the serialized object graph contains a class with a user-defined
|
||||
:php:`__destruct()` or :php:`__wakeup()` method.
|
||||
|
||||
Migration & Insights
|
||||
--------------------
|
||||
|
||||
In most cases no migration is required. The sections below aim to provide
|
||||
some insights into internal details and general suggestions.
|
||||
|
||||
**Cache (**:php:`VariableFrontend`**)**
|
||||
|
||||
No migration is required. Stale or legacy cache entries are automatically
|
||||
treated as misses and regenerated. If code stores object graphs in a
|
||||
:php:`VariableFrontend`-backed cache it will continue to work as long as the
|
||||
server reads the entry it wrote (same encryption key).
|
||||
|
||||
**Registry — preferred approach: avoid object serialization**
|
||||
|
||||
Review what is stored in the registry. Plain PHP arrays and scalar values are
|
||||
not affected by this protection and should be preferred over serialized object
|
||||
graphs wherever possible.
|
||||
|
||||
**Registry — alternative: restructure the stored value**
|
||||
|
||||
If an object must be stored, ensure that neither the object itself nor any
|
||||
object reachable from it through public or serialized properties carries a
|
||||
user-defined :php:`__destruct()` or :php:`__wakeup()` method.
|
||||
|
||||
**Registry — last resort: explicit class allowlist**
|
||||
|
||||
If neither of the above is feasible in the short term, the affected class can be
|
||||
added to the site-level allowlist in :file:`config/system/additional.php` (or
|
||||
the legacy :file:`typo3conf/AdditionalConfiguration.php`):
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SYS']['deserialization']['allowedClassNames'][] =
|
||||
\Vendor\MyExtension\Domain\Model\MyObject::class;
|
||||
|
||||
.. warning::
|
||||
|
||||
The allowlist setting bypasses the deserialization gadget protection for
|
||||
the listed classes. It should only be used as a last resort after carefully
|
||||
reviewing the class and confirming that its :php:`__destruct()` or
|
||||
:php:`__wakeup()` implementation cannot be abused in a PHP object injection
|
||||
attack chain. Remove the entry as soon as the underlying serialization is
|
||||
refactored.
|
||||
|
||||
.. index:: PHP-API, LocalConfiguration, ext:core
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
.. include:: /Includes.rst.txt
|
||||
|
||||
.. _important-92187-1742812030:
|
||||
|
||||
========================================================================
|
||||
Important: #92187 - Evaluation of incoming HTTP Header X-Forwarded-Proto
|
||||
========================================================================
|
||||
|
||||
See :issue:`92187`
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
When running TYPO3 behind a reverse proxy, the site owner needs to set two
|
||||
TYPO3 settings.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyHeaderMultiValue'] = 'first';
|
||||
$GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP'] = '{ip-of-the-reverse-proxy}';
|
||||
|
||||
At this point it is not known if the request between the client (the actual
|
||||
web browser for example) and the reverse proxy was made via HTTP or HTTPS,
|
||||
mainly because TYPO3 only evaluated the information from the reverse proxy
|
||||
to TYPO3 - which was typically faked on the TYPO3's webserver by setting
|
||||
"HTTPS=on" (for example via :file:`.htaccess` file). In a typical setup, the communication
|
||||
between the reverse proxy and TYPO3's webserver is done via HTTP and irrelevant
|
||||
for TYPO3.
|
||||
|
||||
When the site owner knows that the reverse proxy acts as a SSL termination point
|
||||
and only communicates via https to the client, the
|
||||
`$GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxySSL'] <https://docs.typo3.org/permalink/t3coreapi:confval-globals-typo3-conf-vars-sys-reverseproxyprefixssl>`_ option
|
||||
can be set, to identify all reverse proxy IPs that ensure a secure connection
|
||||
between client and reverse proxy.
|
||||
|
||||
In case, it is not known, and
|
||||
`reverseProxyPrefixSSL <https://docs.typo3.org/permalink/t3coreapi:confval-globals-typo3-conf-vars-sys-reverseproxyprefixssl>`_
|
||||
is not in use, but
|
||||
`reverseProxyIP <https://docs.typo3.org/permalink/t3coreapi:confval-globals-typo3-conf-vars-sys-reverseproxyip>`_
|
||||
is in use, the incoming HTTP header `X-Forwarded-Proto` is
|
||||
now evaluated to determine if the request was made, if the header is sent.
|
||||
|
||||
If it is **NOT** sent, TYPO3 will assume to detect a secure connection between
|
||||
SSL information as before via various other HTTP Headers or server configuration
|
||||
settings.
|
||||
|
||||
.. index:: LocalConfiguration, ext:core
|
||||
@@ -0,0 +1,54 @@
|
||||
:template: changelogOverview.html
|
||||
.. include:: /Includes.rst.txt
|
||||
.. _changelog-13-4-x:
|
||||
|
||||
==============
|
||||
13.4.x Changes
|
||||
==============
|
||||
|
||||
**Table of contents**
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
:depth: 1
|
||||
|
||||
|
||||
Breaking Changes
|
||||
================
|
||||
|
||||
None since TYPO3 v13.4.0 LTS release.
|
||||
|
||||
.. attention::
|
||||
|
||||
Breaking changes are not planned after the TYPO3 v13.4.0 LTS release.
|
||||
|
||||
Features
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:titlesonly:
|
||||
:glob:
|
||||
|
||||
Feature-*
|
||||
|
||||
Deprecation
|
||||
===========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:titlesonly:
|
||||
:glob:
|
||||
|
||||
Deprecation-*
|
||||
|
||||
|
||||
Important
|
||||
=========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:titlesonly:
|
||||
:glob:
|
||||
|
||||
Important-*
|
||||
Reference in New Issue
Block a user