Initial situation:
A post in a category has a module embedded (using loadmoduleid or loadposition).
Create a new "Posts" module and add the category containing the aforementioned post to it.
Integrate the "Posts" module into your website.
Result:
When accessing the website (menu item with the "Posts" module), a 500 error appears.
Reason:
The module is being loaded within the module. Memory is being used up.
| Labels |
Removed:
?
|
||
| Labels |
Added:
No Code Attached Yet
|
||
Joomlaplates has solved it this way with its modules (Unfortunately, I cannot upload an MD file, so I'm using a txt file.):
{loadmodule} / {loadposition} in ArtikelnModul: mod_articles (Joomla 5.2+ Core-Modul)
Schweregrad: Kritisch (PHP Fatal Error: Out of Memory)
Betrifft: Joomla 5.x und 6.x
Wenn ein Artikel, der von mod_articles angezeigt wird, im Introtext oder Fulltext einen {loadmodule ...} oder {loadposition ...} Tag enthält, kann es zu einem PHP-Speicherüberlauf (Memory Exhausted) kommen. Die Seite wird nicht mehr geladen und der Server gibt einen HTTP 500 zurück.
1. Seite wird geladen
2. mod_articles lädt Artikel aus der Datenbank
3. Introtext wird mit content.prepare verarbeitet (Content-Plugins laufen)
4. Artikel wird im Frontend angezeigt
1. Seite wird geladen
2. mod_articles lädt Artikel aus der Datenbank
3. Artikel X enthält: {loadmodule mod_articles} oder {loadposition slider}
4. content.prepare verarbeitet den Introtext von Artikel X
5. → plg_content_loadmodule findet {loadmodule mod_articles}
6. → plg_content_loadmodule rendert mod_articles ERNEUT
7. → mod_articles lädt wieder alle Artikel, inkl. Artikel X
8. → content.prepare verarbeitet erneut Artikel X
9. → plg_content_loadmodule findet wieder {loadmodule mod_articles}
10. → Endlosschleife → PHP Speicher voll → Fatal Error
mod_articles
└─ getArticles()
└─ Artikel X (enthält {loadmodule mod_articles})
└─ content.prepare()
└─ plg_content_loadmodule
└─ mod_articles ← REKURSION!
└─ getArticles()
└─ Artikel X
└─ content.prepare()
└─ plg_content_loadmodule
└─ mod_articles ← REKURSION!
└─ ... (endlos)
Datei: src/Helper/ArticlesHelper.php
Methode: getArticles()
$items = $articles->getItems();$item->displayIntrotext = HTMLHelper::_('content.prepare', $item->introtext, '', 'mod_articles.content');HTMLHelper::_('content.prepare', ...) triggert alle Content-Plugins, darunter plg_content_loadmodule. Dieses Plugin sucht nach {loadmodule ...} und {loadposition ...} im HTML und rendert die gefundenen Module — was mod_articles erneut aufruft.
Das Problem: Zwischen dem Laden der Artikel (Zeile 278) und dem Aufruf von content.prepare (Zeile 382) findet keine Prüfung statt, ob ein Artikel problematische Tags enthält.
Direkt nach $articles->getItems() wird ein Filter eingefügt, der Artikel mit {loadposition oder {loadmodule vor der Verarbeitung entfernt:
$items = $articles->getItems();
// Prevent infinite recursion: remove articles containing {loadposition} or
// {loadmodule} before content plugins run.
$items = array_values(array_filter($items, function ($item) {
$text = ($item->introtext ?? '') . ($item->fulltext ?? '');
return stripos($text, '{loadposition') === false
&& stripos($text, '{loadmodule') === false;
}));| Ansatz | Bewertung |
|---|---|
SQL-Filter (NOT LIKE) |
Möglich, aber der Articles-Model-State unterstützt keinen Content-Text-Filter. Müsste das Model hacken. |
| Post-Load Filter (gewählt) | Sicher, einfach, kein Eingriff in das Core-Model. Filter läuft nach dem DB-Query aber vor content.prepare. |
| Rekursions-Zähler | Fragil, schwer zu debuggen, löst das Problem nicht an der Wurzel. |
content.prepare und nicht danach?Der Artikel darf gar nicht erst in die Plugin-Pipeline gelangen. Wenn content.prepare einmal aufgerufen wird, ist die Rekursion bereits gestartet, bevor ein nachgelagerter Filter greifen könnte.
| Szenario | Ohne Fix | Mit Fix |
|---|---|---|
Artikel ohne {loadmodule} |
Normal angezeigt | Normal angezeigt |
Artikel mit {loadmodule mod_articles} |
Memory Overflow | Artikel wird übersprungen |
Artikel mit {loadposition xyz} (Position enthält mod_articles) |
Memory Overflow | Artikel wird übersprungen |
Artikel mit {loadmodule mod_menu} (kein mod_articles) |
Funktioniert zufällig | Artikel wird übersprungen* |
*Konservativer Ansatz: Auch {loadmodule mod_menu} wird gefiltert, da nicht feststellbar ist, ob die geladene Position/Modul-Instanz wiederum mod_articles enthält. Sicherheit geht vor.
mod_articles auf einer Seite einbindenDies ist ein Testartikel. {loadmodule mod_articles}
mod_articles anzeigt{loadmodule} wird nicht angezeigt (korrekt)mod_articles/src/Helper/ArticlesHelper.php — Filter nach getItems(), vor der foreach-SchleifeI can reproduce the effect. The AI generated solution in #46899 (comment) however, which removes all loadmodules from articles before rendering a mod_articles seems not appropriate.
I suggest to close this #39529 (comment)
Do i understand correctly that the problem only occurs when you have an article that is loading articles embedded into it causing the recursion and not a general problem with any embedded module. If so then I would file this under won't fix as at the end of the day its the user who is creating the endless loop by their own action and not Joomla AND there would be no way programatically to prevent this.
It's about posts in which a module is loaded, and then this post, including the module, is loaded again into the module posts. The user cannot know that something like this (a module in the post) will then produce an error in the module view of posts.
why would you ever do that? the proposed solution would remove all modules even if they wouldnt cause a recursive loop - that would not be a sensible solution
We implemented it in our JoomlaPlates UIKIT modules as I've shown in the code. This avoids this loop and 500 errors in the frontend. There should still be a better solution, though. Do you have a better idea, Brian?
no
We have now solved it so that the user can decide whether it is excluded or not.
It crashes when the "Show introductory text" option is enabled in the module and only one post from the selected categories loads a module (i.e., something with
loadmoduleidis included in the post).Then you get a 500 error in the frontend for that page.
This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/46899.