TYPO3 Forge: Issueshttp://forge.typo3.org/http://forge.typo3.org/themes/typo3_forge/favicon/favicon.png?17058661692023-10-13T09:40:45ZTYPO3 Forge
Redmine TYPO3 Core - Bug #102161 (New): f:link.page and f:uri.page (UriBuilder) are impossible to use wit...http://forge.typo3.org/issues/1021612023-10-13T09:40:45ZClaus Dueclaus@phpmind.net
<p>There is a conflict in the internal type requirements of the "language" argument on UriBuilder and PageLinkBuilder:</p>
<ul>
<li>If you do what UriBuilder says and pass the language ID as a string, you get `TYPO3\CMS\Core\Context\LanguageAspect::__construct(): Argument #1 ($id) must be of type int, string given, called in cms-frontend/Classes/Typolink/PageLinkBuilder.php on line 416`.</li>
<li>If you do what this error message implies and pass language ID as an integer, you get `TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder::setLanguage(): Argument #1 ($language) must be of type ?string, int given, called in cms-fluid/Classes/ViewHelpers/Link/PageViewHelper.php on line 261`.</li>
</ul>
<p>The result is a deadlock where it is impossible to specify the desired language when creating a link through UriBuilder.</p>
<p>The problem is in \TYPO3\CMS\Frontend\Typolink\PageLinkBuilder::resolvePage, which indiscriminately uses the $configuration['language'] variable and assumes it's an integer (if it is not a string "current") and passes this value to the constructor of LanguageAspect.</p>
<p>The right solution is to do what the build() method on PageLinkBuilder does:</p>
<pre><code class="php syntaxhl" data-language="php"> <span class="k">if</span> <span class="p">(</span><span class="k">isset</span><span class="p">(</span><span class="nv">$configuration</span><span class="p">[</span><span class="s1">'language'</span><span class="p">])</span> <span class="o">&&</span> <span class="nv">$configuration</span><span class="p">[</span><span class="s1">'language'</span><span class="p">]</span> <span class="o">!==</span> <span class="s1">'current'</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$siteOfTargetPage</span> <span class="o">=</span> <span class="nc">GeneralUtility</span><span class="o">::</span><span class="nf">makeInstance</span><span class="p">(</span><span class="nc">SiteFinder</span><span class="o">::</span><span class="n">class</span><span class="p">)</span><span class="o">-></span><span class="nf">getSiteByPageId</span><span class="p">((</span><span class="n">int</span><span class="p">)</span><span class="nv">$page</span><span class="p">[</span><span class="s1">'uid'</span><span class="p">]);</span>
<span class="nv">$siteLanguageOfTargetPage</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getSiteLanguageOfTargetPage</span><span class="p">(</span><span class="nv">$siteOfTargetPage</span><span class="p">,</span> <span class="p">(</span><span class="n">string</span><span class="p">)(</span><span class="nv">$conf</span><span class="p">[</span><span class="s1">'language'</span><span class="p">]</span> <span class="o">??</span> <span class="s1">'current'</span><span class="p">));</span>
<span class="nv">$languageAspect</span> <span class="o">=</span> <span class="nc">LanguageAspectFactory</span><span class="o">::</span><span class="nf">createFromSiteLanguage</span><span class="p">(</span><span class="nv">$siteLanguageOfTargetPage</span><span class="p">);</span>
<span class="nv">$page</span> <span class="o">=</span> <span class="nv">$pageRepository</span><span class="o">-></span><span class="nf">getLanguageOverlay</span><span class="p">(</span><span class="s1">'pages'</span><span class="p">,</span> <span class="nv">$page</span><span class="p">,</span> <span class="nv">$languageAspect</span><span class="p">);</span>
<span class="p">}</span>
</code></pre>
<p>This would also have the side effect of actually respecting language fallback when resolving the translated version of a page.</p> TYPO3 Core - Task #101698 (Under Review): Remove "final" keywordhttp://forge.typo3.org/issues/1016982023-08-16T11:28:02ZClaus Dueclaus@phpmind.net
<p>More and more classes are marked as "final" in TYPO3.</p>
<p>This should not be done unless in very specific circumstances:</p>
<ul>
<li>For security reasons, e.g. when a class name can be selected from an exposed option like a form field, and only when such implementations share an interface and the entire application programs against the interface, not the implementation.</li>
<li>And that's basically it.</li>
</ul>
<p>And it should <strong>never</strong> be done on a class that does not have an interface and where the rest of the framework programs against the specific implementation instead of the interface.</p>
<p>Using "final" as a way to signal that "you shouldn't replace this class" is an abuse of the language construct. Signals should be sent with interfaces or annotations - not by enforcing it as an unavoidable choice imposed on every developer.</p>
<p>The classes that currently declare "final" as well as those that are scheduled to become "final" simply do not fulfill this.</p>
<p>Additionally, "final" without a programmed-to interface is poison for testability in that it prevents the (efficient) creation of test doubles.</p>
<p>Therefore, the "final" keyword should be removed and avoided in the future.</p> TYPO3 Core - Bug #101531 (Needs Feedback): \TYPO3\CMS\Frontend\Middleware\PreviewSimulator::check...http://forge.typo3.org/issues/1015312023-08-02T14:06:04ZClaus Dueclaus@phpmind.net
<p>When EXT:workspaces is installed, every frontend request where a BE user is logged in, triggers a <abbr title="">TRUNCATE</abbr> on both cache_rootline and cache_rootline_tags. This causes this cache to become empty for any subsequent frontend request, which causes terrible performance with multiple unnecessary SQL requests.</p>
<p>Additionally, it may cause the rootline cache to contain incorrect information (cache entries generated based on workspace state will be fetched by subsequent requests causing things like rootlines or access checks to potentially fail).</p>
<p>The problem occurs because \TYPO3\CMS\Frontend\Middleware\PreviewSimulator::checkIfRootlineRequiresPreview will indiscriminately flush this cache in the "finally" block of an exception catch, without any regard for whether or not a workspace other than LIVE is actually active.</p>
<p>Both of these problems - as well as multiple other potential cache-related problems stemming from the need to preview workspaces - may be completely circumvented by allowing CacheManager API to replace an active cache. The idea being that instead of indiscriminately flushing this and other caches, the cache backend can instead be replaced with a NullBackend on-the-fly when \TYPO3\CMS\Frontend\Middleware\PreviewSimulator::checkIfRootlineRequiresPreview determines that a workspace preview is necessary. Plus, only replacing these cache backends BE user's selected workspace is a non-LIVE workspace.</p>
<p>Doing so would mean that:</p>
<ul>
<li>There are no possible issues from a cached value that doesn't match the workspace state.</li>
<li>The performance hit is isolated to whenever a workspace preview is actually happening.</li>
<li>The actual cache is preserved and remains unmodified, removing the negative impact on other requests.</li>
<li>No entries will be written to the substituted caches, removing the risk of retaining cached data that applies only to a workspace.</li>
</ul> TYPO3 Core - Task #94841 (Rejected): Unit test coverage of Fluid can be improvedhttp://forge.typo3.org/issues/948412021-08-12T13:43:39ZClaus Dueclaus@phpmind.net
<p>We currently only cover a marginal percentage of (non-ViewHelper) Fluid classes with unit tests. This coverage can and should be improved.</p> TYPO3 Core - Bug #94158 (New): Select type selectSingle fields (and likely other renderTypes too)...http://forge.typo3.org/issues/941582021-05-19T12:34:33ZClaus Dueclaus@phpmind.net
<a name="Example-TCA"></a>
<h3 >Example TCA:<a href="#Example-TCA" class="wiki-anchor">¶</a></h3>
<pre>
'field' => [
'label' => 'LLL:EXT:myext/Resources/Private/Language/locallang_db.xlf:table.field',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'foreign_table' => 'tx_foo',
'eval' => 'null',
],
],
</pre>
<a name="Expectation"></a>
<h3 >Expectation:<a href="#Expectation" class="wiki-anchor">¶</a></h3>
<p>Field should render with the "Set value" checkbox identical to how eval=null works on for example simple input fields.</p>
<a name="Current-behavior"></a>
<h3 >Current behavior:<a href="#Current-behavior" class="wiki-anchor">¶</a></h3>
<p>Option eval=null is ignored and does not render a "Set value" checkbox above the field.</p>
<a name="References"></a>
<h3 >References:<a href="#References" class="wiki-anchor">¶</a></h3>
<p>Similarly reported for RTE fields on <a class="external" href="https://forge.typo3.org/issues/88480">https://forge.typo3.org/issues/88480</a></p> TYPO3 Core - Bug #93811 (Closed): Image processing is inconsistent between FilesProcessor and Med...http://forge.typo3.org/issues/938112021-03-24T11:08:08ZClaus Dueclaus@phpmind.net
<p>Note, the following is reported with .ai / .eps formats which I'm aware aren't natively supported as images. However, the issue still remains the same - FilesProcessor seems to use the correct API for processing files whereas Media/ImageViewHelper takes a shortcut that potentially causes errors when processing files that are image-incompatible, e.g. videos or PDF.</p>
<p>An alternative problem description could also be "Image processing ignores TYPO3_CONF_VARS.GFX.imagefile_ext when determining if file is an image".</p>
<p><strong>Problem description:</strong></p>
<p>Files of types like "ai" or "eps" do not get scaled when using FilesProcessor, but do get scaled when using MediaViewHelper. This is due to using different APIs:</p>
<ul>
<li>FilesProcessor will use FileUtility which has a condition that checks File->getType equal to "image" before doing image processing; if matched it then uses ImageService to apply processing.</li>
<li>But MediaViewHelper directly uses ImageService to perform processing and will therefore scale/crop literally any file that can be cropped/scaled by the configured image processing mechanism (im, gm, gd)</li>
</ul>
<p>This causes two side effects:</p>
<ul>
<li>Media processing is inconsistent between FilesProcessor and MediaViewHelper</li>
<li>MediaViewHelper will explicitly treat every type of media as an "image", including videos/pdf/etc.</li>
</ul>
<p><strong>Fix for TYPO3 long-term:</strong></p>
<p>Solve inconsistency between FilesProcessor and MediaViewHelper. Problem is, FilesProcessor uses FileUtility to process which supports all file formats, but contains a condition that only uses File->getType to determine if file is an image. If not an image, no scaling/cropping is performed.</p>
<ul>
<li>Solution 1: Make MediaViewHelper also use FileUtility to do processing for consistency. Does not solve the issue that File->getType must be "image" or no processing happens, but does introduce full consistency between the two APIs.</li>
<li>Solution 2: Do solution 1 + add a condition in FileUtility that also considers any File that has a file extension that is recorded in TYPO3_CONF_VARS.GFX.imagefile_ext as being an "image", regardless of File->getType return value. Solves both the inconsistency and the problem of eps/ai/etc. not being detected as image regardless of configuration.</li>
<li>Solution 3: Do solution 1 + change determination of "type" for File when uploaded, to also consider any file extension recorded in TYPO3_CONF_VARS.GFX.imagefile_ext to be an "image". Solves both issues but does not retroactively fix files that are already uploaded (solution 2 probably preferable).</li>
</ul> TYPO3 Core - Bug #93095 (Under Review): Persistence Session->hasIdentifier() triggers PHP warning...http://forge.typo3.org/issues/930952020-12-17T10:37:30ZClaus Dueclaus@phpmind.net
<p>When calling Session->hasIdentifier() with an identifier that does not exist (because no object of that class type has been fetched), the function will internally call:</p>
<pre><code>return isset($this->identifierMap[$this->getClassIdentifier($className)][$identifier]);</code></pre>
<p>However, $this->identifierMap[$this->getClassIdentifier($className)] will be NULL which means that PHP will attempt to check if `null[$identifier]` is set, which then triggers the warning.</p>
<p>Suggested fix:</p>
<pre><code>$classIdentifier = $this->getClassIdentifier($className);<br /> return isset($this->identifierMap[$classIdentifier], $this->identifierMap[$classIdentifier][$identifier]);</code></pre>
<p>By passing two arguments to isset() the function will return false immediately if the first reference is not set, which in the described use case, it isn't. This then prevents the second reference - which would cause the warning to be triggered - from being evaluated.</p> TYPO3 Core - Bug #93049 (New): Backend user must have write privileges for exclude field be_users...http://forge.typo3.org/issues/930492020-12-10T15:06:26ZClaus Dueclaus@phpmind.net
<p>Not sure if this is a bug or by design. If by design, a FlashMessage would be nice when a user attempts to change their password without the necessary access. Currently, an OK FlashMessage is dispatched which says "Password updated" even if the password update is ignored.</p>
<p>When a non-admin user uses "User Settings" to update their password, the update is silently rejected if the user(-group) does not have edit access for the specific field be_users.password, since this field is filtered out in DataHandler when processing exclude fields.</p>
<p>Observed on 9.5 but most likely behaves the same on all versions.</p> TYPO3 Core - Task #92059 (Closed): Message->isValidHeaderValue uses inefficient string parsinghttp://forge.typo3.org/issues/920592020-08-20T17:53:51ZClaus Dueclaus@phpmind.net
<p>Message->isValidHeaderValue currently uses a combination of "for", "strlen" and "ord" on individual substring offsets to iterate over the bytes of a string.</p>
<p>This is possible to achieve with "unpack" which reduces memory usage and random substring access. Potentially saving thousands of calls to "ord" and one call to "strlen" per header.</p> TYPO3 Core - Bug #91729 (New): Frontend 404 handling incorrectly reports "group access denied" if...http://forge.typo3.org/issues/917292020-06-30T10:56:02ZClaus Dueclaus@phpmind.net
<p><strong>Observed on 8.7 but should be exactly the same up to and including v10.4</strong></p>
<p><strong>Set to "must have" since this causes major inconsistency in information transmitted to 404 handlers</strong></p>
<p>Consider the following code from TypoScriptFrontendController->getPageAccessFailureReasons:</p>
<pre>
$combinedRecords = array_merge(is_array($this->pageAccessFailureHistory['direct_access']) ? $this->pageAccessFailureHistory['direct_access'] : [['fe_group' => 0]], is_array($this->pageAccessFailureHistory['sub_section']) ? $this->pageAccessFailureHistory['sub_section'] : []);
if (!empty($combinedRecords)) {
// Generate failure reason
}
</pre>
<p>If $this->pageAccessFailureHistory['direct_access'] is EMPTY, a virtual entry is generated here which 1) has no page UID as key, and 2) says that fe_group is zero.</p>
<p>This then makes the !empty() check return TRUE (because $combinedRecords contains this virtual entry) and enter the condition which generates an incorrect failure reason that is then transmitted to registered 404 handlers.</p>
<p>Handlers receive the following incorrect information:</p>
<ul>
<li>Failure happened because of group access (wrong, it happened because a page was not resolved)</li>
<li>UID of page is zero (wrong, no such page can exist)</li>
<li>UID of group that caused the failure is zero (wrong, this would always have to be a valid ID or special keyword -2)</li>
</ul>
<p>In short, it makes the 404 error appears like a "group access denied" error.</p>
<p>The reason for the incorrect behavior is the falling back to a virtual "direct_access" group restriction error. Removing this part correctly identifies the 404 error as a "page not found".</p> TYPO3 Core - Bug #91697 (New): Access protecting root page results in "page not found" when user ...http://forge.typo3.org/issues/916972020-06-23T13:01:28ZClaus Dueclaus@phpmind.net
<p>This is a rather complex bug. It triggers when:</p>
<ul>
<li>You configure the root page of a domain to be access protected</li>
<li>TypoScriptFrontendController attempts to resolve the page, but does not disable access checks</li>
<li>An early guard clause triggers pageNotFound handling because page is not resolved - but root line is NOT empty</li>
<li>This prevents the true group access checks from triggering</li>
</ul>
<p>The result is that any custom class registered for page-not-found handling is told the page does not exist, when it fact it does exist but is merely access protected. And this in turn prevents such a custom class from handling this particular case as an access failure case.</p>
<p>It is possible to work around this:</p>
<pre>
if (empty($parameters['pageAccessFailureReasons']) && count($controller->rootLine) === 1) {
// No reason was provided and the root line contains a single entry. Check the only page that is in the
// root line and determine if it was access protected. If it is access protected, return true.
// Perform the access check by repeating a call to get the page record, but with access check enabled.
$pageIsRootAndNotAccessibleByUserGroup = !$controller->checkPageGroupAccess($controller->rootLine[0]);
}
</pre>
<p>Suggested fix:</p>
<p>In \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::getPageAndRootline, in the second check for "if (empty($this->page))", check if:</p>
<ul>
<li>Root line contains a single entry (the requested page was the root page and it exists)</li>
<li>$this->checkPageGroupAccess($this->rootline<sup><a href="#fn0">0</a></sup>) returns false</li>
</ul>
<p>If fulfilled:</p>
<ul>
<li>Set $this->pageNotFound = 1 indicating that failure reason is that page is not accssible</li>
<li>Set $this->pageAccessFailureHistory['direct_access'][] = $this->rootline<sup><a href="#fn0">0</a></sup>;</li>
<li>call $this->pageNotfoundAndExit('The requested page was not accessible!', $GLOBALS['TYPO3_CONF_VARS']['FE']['pageUnavailable_handling_statheader']); instead of calling $this->pageNotFoundAndExit('The requested page does not exist!');</li>
</ul>
<p>This causes the same check and failure reason for a request made directly to a protected root page, as would trigger for a request made directly to a protected sub-page.</p>
<p>Bug is encountered on 8.7 but almost certainly exists on all versions up to and after 10 LTS.</p>
<p>Set to "must have" as this bug is a serious inconsistency that prevents proper use of custom page-not-available handling.</p> TYPO3 Core - Bug #91456 (Closed): ExtensionManager allows deleting inactive packages when compose...http://forge.typo3.org/issues/914562020-05-21T13:07:01ZClaus Dueclaus@phpmind.net
<p>As described in subject line, EM will allow you to delete the files of an extension that is inactive, even when composer mode is enabled. Doing so might break a site and shouldn't logically be possible since Composer would be solely responsible for managing the presence of files.</p>
<p>Alternatively, EM should scan the project composer.lock file to determine if an extension is truly not managed by Composer, before allowing deletion of the extension files.</p> TYPO3 Core - Bug #91255 (Closed): PHP Warning: "continue" targeting switch is equivalent to "bre...http://forge.typo3.org/issues/912552020-05-01T13:43:41ZClaus Dueclaus@phpmind.net
<p>In TYPO3 9.5, the ExtensionManagementUtility's `addToAllTCAtypes` method contains a loop with a switch inside. The "replace" switch cases attempts to continue to loop without providing a continuation level and this raises the above mentioned PHP warning.</p>
<pre>
foreach ($paletteNames as $paletteName) {
// TRUNCATED EXAMPLE
switch ($positionIdentifier) {
case 'after':
case 'before':
// TRUNCATED EXAMPLE
break;
case 'replace':
// TRUNCATED EXAMPLE (2 occurrences total)
continue;
continue;
break;
default:
// Intentionally left blank
}
}
</pre>
<p>Can be easily fixed by using `continue 2` instead of simply `continue`.</p> TYPO3 Core - Bug #91127 (Closed): "Starting module" is never resolved from first available modulehttp://forge.typo3.org/issues/911272020-04-19T13:57:57ZClaus Dueclaus@phpmind.net
<p>When UC is empty, the first available module is not detected since \TYPO3\CMS\Backend\Controller\BackendController::determineFirstAvailableBackendModule is never called. This is because $beUser->uc['startModule'] is always filled but does not get filled with the first available module from the list - rather, it gets filled with the <strong>last</strong> available module.</p>
<p>Note that EXT:dashboard must be uninstalled since this extension forces itself to be the default starting module and therefore hides the misbehavior.</p> TYPO3 Core - Task #90946 (Closed): Fluid-based page layout module should render record preview th...http://forge.typo3.org/issues/909462020-04-04T15:48:38ZClaus Dueclaus@phpmind.net
<p>The Fluid based page module currently renders records previews as part of the Record.html partial which is relatively large.</p>
<p>In order to allow globally overriding only the "preview" output section, a dedicated partial should be created for the Preview rendering.</p>