LimeSurvey 7.0.5 → 7.0.6

Eine technische Analyse

Kopfdaten und Grenzen

Release
7.0.5 → 7.0.6
Commits
64
Geänderte Dateien
1083
Analyse
10.08.2026
Schwerpunkt
Ranking-Datenmodell, Editorausbau, Abhängigkeiten

Nicht untersucht

Verglichen wurden die im lokalen Repository verifizierten Tags 7.0.5+260623 (23.06.2026) und 7.0.6+260722 (
22.07.2026) mit git log --oneline 7.0.5+260623..7.0.6+260722 und git diff --shortstat 7.0.5+260623..7.0.6+260722.
Nicht ausgewertet wurden der Inhalt des mitgelieferten vendor/-Baums (837 der 1083 geänderten Dateien), die kompilierten Bundles unter editor/build/ und assets/packages/*/build, die minifizierten Admin-Theme-Stylesheets sowie die Übersetzungsdateien. Dadurch bleibt offen, ob die Umstellung der Tabellenkalkulations-Bibliothek und der Sprung des DI-Containers über die zitierten Quelldateien hinaus weitere Verhaltensänderungen mitbringen. Indirekte Effekte über transitive Drittabhängigkeiten lassen sich durch reine Diff-Analyse nicht vollständig erfassen. Aus dem Kapitel „Weitere relevante Änderungen" wurden neun Einträge geringerer Relevanz weggelassen, darunter der Wegfall obsoleter PHP-Versionsprüfungen, die Feldnamen-Ersetzung beim Gruppenimport, der Nullwert-Umgang im SPSS-Export und der Identity-Insert-Umgang bei der Wiederherstellung archivierter Antworten unter SQL Server.

Executive Summary

Dieses Release verschiebt das Speicherformat der Rangfolgefrage: Statt einer Spalte je Unterfrage hält die Antworttabelle künftig ein JSON-Array je Frage, und die Migration auf die interne Datenbankversion 709 löscht die bisherigen Spalten in laufenden Umfragen.
Daneben wechselt der Abhängigkeitsunterbau — der DI-Container liest PHP-Attribute statt Docblock-Annotationen, und der Statistikexport verlässt das binäre XLS-Format. Am ehesten unbemerkt bleibt die Rangfolge-Migration: Sie läuft ohne Rückfrage, ist nicht rückwärtskompatibel, und nachgelagerte Auswertungen, die die alten Spaltennamen kennen, liefern danach entweder einen Fehler oder gar nichts mehr.
Ebenfalls leise ist die neue Sitzungsbehandlung bei abweichendem Zugangscode, die in eigenen Themes ohne angepasstes Fehlerlayout zu einer Sackgasse ohne Neustart-Link führt.

  1. Ranking-Antworten werden als JSON gespeichert
  2. Sitzung bleibt bei abweichendem Zugangscode bestehen
  3. Der DI-Container liest PHP-Attribute statt Annotationen
  4. Statistikexport als XLSX und entfernte Composer-Pakete
  5. XSS im Bestätigungsdialog der Benutzeraktivierung
  6. Umbenannte Modellmethoden und geänderte Fragethemen-Konvertierung
  7. Schreibgeschützte Fragenattribute werden serverseitig erzwungen
  8. Rasteransichten mit seitenübergreifender Auswahl

Upgrade-Empfehlung

🧪 Vorher testen

Die Migration auf die interne Datenbankversion 709 löscht Spalten in den Antworttabellen aktiver Umfragen und ist damit nicht ohne Sicherung umkehrbar. Erweiterungen, die den DI-Container oder die umbenannten Modellmethoden verwenden, brechen zur Laufzeit. Ein Testlauf auf einer Kopie der Produktivdatenbank ist vor dem Update angezeigt.

Lesepfad

ZielgruppeRelevante Kennungen und Kapitel
AdministratorenA1, A2, A3, A4, A5, A7, Weitere relevante Änderungen, Empfehlung
Plugin-EntwicklerA1, A3, A4, A6, A7, A8, Weitere relevante Änderungen, Empfehlung
Theme-EntwicklerA2, A6, A8, Weitere relevante Änderungen, Empfehlung
IntegratorenA1, A2, A4, A5, A6, Weitere relevante Änderungen, Empfehlung
API-NutzerA1, Weitere relevante Änderungen, Empfehlung

Die wichtigsten Änderungen

A1: Ranking-Antworten werden als JSON gespeichert

Sicherheitsrelevanz
Keine
Handlungsdruck
Hoch
Bruchverhalten
Stiller Fehler
Betroffen
Administratoren, Integratoren, API-Nutzer, Plugin-Entwickler

Hintergrund: Die Rangfolgefrage legte bisher für jede Unterfrage eine eigene Spalte Q<qid>_S<sqid> in der Antworttabelle an, deren Wert der an dieser Position gewählte Antwortcode war. Das Release ersetzt diese Aufteilung durch eine einzelne Spalte Q<qid> vom Typ json, die die gerankten Elemente als geordnetes Array hält. Dafür erhalten die drei Schemaklassen für MySQL, PostgreSQL und SQL Server einen neuen Spaltentyp; unter SQL Server wird er aufnvarchar(max) abgebildet. Die Fragethemen-Definition der Rangfolge wechselt von Antwortskalen auf Unterfragen, die Unterfragen selbst erhalten in der Fragentabelle den Typ R, und der Expression Manager fasst die Einzelfelder beim Speichern einer Antwort zu einem JSON-Wert zusammen.

Konsequenz: Beim Update wird für jede aktive Umfrage mit Rangfolgefragen eine neue Spalte angelegt, aus den bestehenden Werten befüllt und die bisherigen Spalten werden gelöscht. Auswertungen, die direkt auf der Antworttabelle arbeiten — SQL-Views, BI-Anbindungen, eigene Exportskripte — finden die Spalten Q<qid>_S<sqid> danach nicht mehr vor. Exporte, Antwortanzeige, quexml und die REST-Antwortliste liefern für Rangfolgefragen künftig einen zusammengefassten Wert statt einer Spalte je Rang. Die Migration greift laut der zitierten Auswahlabfrage ausschließlich für Umfragen mitactive = 'Y'; für inaktive Umfragen entsteht die neue Struktur erst bei der nächsten Aktivierung. Offen bleibt, ob vorhandene Zeilen der Fragethemen-Tabelle an die geänderte Themendefinition angeglichen werden: Im Diff ist dafür keine Migration erkennbar, und die geänderten Vorgabewerte in den Standarddatensätzen greifen erkennbar nur bei Neuanlage.

Vorher / Nachher:

// Vorher (application/config/version.php)
$config['versionnumber'] = '7.0.5';
$config['dbversionnumber'] = 708;
// Nachher
$config['versionnumber'] = '7.0.6';
$config['dbversionnumber'] = 709;
// Neu (application/helpers/update/updates/Update_709.php)
protected function alterMySQL(int $sid, int $parent_qid, array $cols)
{
    addColumn("{{responses_" . $sid . "}}", "Q{$parent_qid}", "JSON");
    ...
    $updateCommand = "UPDATE {{responses_" . $sid . "}} SET Q{$parent_qid} = CONCAT('[', " . implode($alterElements) . " ']')";
    $this->db->createCommand($updateCommand)->execute();
    foreach ($cols as $col) {
        dropColumn("{{responses_" . $sid . "}}", $col);
    }
}
// Neu (application/helpers/update/updates/Update_709.php)
$rankingQuestionQuery = "
    SELECT s.sid AS sid, q1.qid AS parent_qid, q2.qid AS qid
    FROM {{surveys}} s
    JOIN {{questions}} q1
    ON s.sid = q1.sid AND s.active = 'Y'
    ...
";

Neuer Bezugswert: Die Rangposition ergibt sich künftig aus der Reihenfolge der Elemente im JSON-Array der Spalte Q<qid>; der Index null entspricht Rang eins. Die Aufbereitung für die Anzeige zeigt dieselbe Ableitung:

// Neu (application/helpers/common_helper.php)
$indexedQuestions = [];
foreach ($items as $index => $item) {
    if (isset($titleToText[$item])) {
        $rank = $index + 1;
        $indexedQuestions[] = gT('Rank', null, $sLanguage) . " {$rank}: {$titleToText[$item]}";
    }
}

Migrationsdetails: Die interne Datenbankversion steigt laut Zitat von 708 auf 709. Die Migration ist Struktur- und Wertänderung zugleich: Sie legt eine Spalte an, befüllt sie per UPDATE und entfernt anschließend die Ursprungsspalten per dropColumn. Eine Rückwärtskompatibilität besteht damit nicht, da die Ausgangsdaten nach dem Lauf nur noch im JSON-Feld vorliegen. Die Idempotenz ist aus dem Zitat nicht bestimmbar, da der zitierte Code kein Vorhandensein der Zielspalte prüft.

Nach dem Update testen: Eine aktive Umfrage mit Rangfolgefrage öffnen, die Antworttabelle auf die Spalte Q<qid> prüfen und einen Datensatz gegen den vor dem Update gesicherten Stand vergleichen. Anschließend einen CSV- und einen SPSS-Export sowie die Antwortdetailansicht aufrufen und prüfen, ob die Rangfolge vollständig und in der erwarteten Reihenfolge erscheint. Zuletzt eine inaktive Umfrage mit Rangfolgefrage aktivieren und die erzeugte Spaltenstruktur kontrollieren.

Betroffene Dateien:

Relevante Commits:

A2: Sitzung bleibt bei abweichendem Zugangscode bestehen

Sicherheitsrelevanz
Keine
Handlungsdruck
Mittel
Bruchverhalten
Stiller Fehler
Betroffen
Administratoren, Theme-Entwickler, Integratoren

Hintergrund: Rief eine teilnehmende Person eine Umfrage mit einem Zugangscode auf, der nicht zu dem in der Sitzung hinterlegten Code passte, beendete der Umfrage-Controller bisher die laufende Sitzung und legte unmittelbar eine neue an. Das Release entfernt diesen Aufruf: Stattdessen wird eine Hinweisseite mit einem Neustart-Link ausgeliefert, der die Kennung newtest=Y trägt und die Sitzung erst beim ausdrücklichen Klick zurücksetzt. Die Meldung selbst wurde auf drei Textbausteine erweitert, und die Fehlerlayouts der beiden mitgelieferten Umfrage-Themes geben nun zusätzlich das FeldaError.URL aus.

Konsequenz: Öffnet jemand einen zweiten Umfragelink mit anderem Zugangscode in demselben Browser, geht der Fortschritt der ersten Sitzung nicht mehr verloren. Der Effekt greift nur dort, wo das Fehlerlayout des verwendeten Themes den neuen URL-Block enthält. Eigene Themes, die layout_errors.twig überschreiben und aus einem älteren Stand stammen, zeigen die Meldung ohne den Neustart-Link — die teilnehmende Person landet dann in einer Sackgasse, ohne dass ein Fehler protokolliert wird. Für Integrationen, die den bisherigen automatischen Neustart als Verhalten voraussetzen — etwa Wiedereinstiegslinks aus einem Kampagnenwerkzeug —, endet der Aufruf künftig auf einer Zwischenseite statt direkt in der Umfrage.

Vorher / Nachher:

// Vorher (application/controllers/survey/SurveyIndex.php)
killSurveySession($surveyid);

App()->getController()->renderExitMessage(
    $surveyid,
    'restart-survey',
// Nachher
// Do NOT kill the existing session here: opening the survey with a different
// access code (e.g. in another browser tab) must not silently overwrite or
// discard the session that is already in progress (see issue #20598).
// The session is only reset when the participant explicitly clicks the link
// above, which carries "newtest=Y" and triggers killSurveySession() on entry.
App()->getController()->renderExitMessage(
{# Neu (themes/survey/vanilla/views/layout_errors.twig) #}
{% if aError.URL %}
    <div class="card-text">{{ aError.URL }}</div>
{% endif %}

Nach dem Update testen: In einem Browser eine tokenbasierte Umfrage bis zur zweiten Seite ausfüllen, dann in einem
zweiten Tab denselben Umfragelink mit einem anderen Zugangscode öffnen und prüfen, ob die Hinweisseite erscheint und der
erste Tab nach dem Zurückspringen weiterhin den gespeicherten Fortschritt zeigt. Denselben Ablauf mit jedem produktiv
eingesetzten eigenen Theme wiederholen und kontrollieren, ob der Neustart-Link sichtbar ist.

Betroffene Dateien:

Relevante Commits:

A3: Der DI-Container liest PHP-Attribute statt Annotationen

Sicherheitsrelevanz
Keine
Handlungsdruck
Hoch
Bruchverhalten
Fehler zur Laufzeit
Betroffen
Plugin-Entwickler, Administratoren

Hintergrund: Der Dependency-Injection-Container wurde bisher mit aktivierter Annotationsauswertung gebaut und erkannte Injektionspunkte an einem @Inject-Eintrag im Docblock. Das Release hebt den Container auf eine neue Hauptversion, entfernt das Annotationspaket aus den Abhängigkeiten und schaltet die Erkennung auf PHP-Attribute um. Die Kernklassen wurden entsprechend umgeschrieben.

Konsequenz: Erweiterungen, die eigene Dienste über den Container beziehen und ihre Injektionspunkte als Docblock-Annotation auszeichnen, werden nicht mehr befüllt. Da die betroffenen Eigenschaften in der Regel typisiert sind, äußert sich das als Laufzeitfehler beim ersten Zugriff, nicht beim Laden des Plugins. Betroffen ist außerdem, wer seine Installation selbst aus den Paketquellen baut: Der Lauf des Abhängigkeitsmanagers zieht den Container in der neuen Hauptversion und entfernt das Annotationspaket, sodass Code, der es direkt einbindet, den Klassenlader nicht mehr bedienen kann. Wer das mitgelieferte vendor/-Verzeichnis verwendet, erhält den Stand unverändert mit dem Release.

Vorher / Nachher:

// Vorher (application/libraries/DI.php)
$builder->useAnnotations(true);
// Nachher
$builder->useAttributes(true);
// Vorher (application/models/services/SurveyDeactivate.php)
/** @Inject("archivedTokenSettings") */
private ArchivedTableSettings $archivedTokenSettings;
// Nachher
#[\DI\Attribute\Inject('archivedTokenSettings')]
private ArchivedTableSettings $archivedTokenSettings;

Konfiguration: Die Änderung verschiebt einen Eintrag in composer.json. Wer aus den Paketquellen baut, benötigt
dort den Container in der neuen Hauptversion; der Eintrag "doctrine/annotations": "~1.10" entfällt.

composer.json, vorher:

"php-di/php-di": "6.4.0",
"doctrine/annotations": "~1.10",

composer.json, nachher:

"php-di/php-di": "^7.0",

Nach dem Update testen: Jede eigene Erweiterung, die den Container verwendet, im Administrationsbereich aktivieren
und die von ihr bereitgestellte Funktion einmal vollständig aufrufen; im PHP-Fehlerprotokoll auf Meldungen zu nicht
initialisierten typisierten Eigenschaften prüfen. Bei Eigenbau zusätzlich einen vollständigen Lauf des
Abhängigkeitsmanagers ausführen und danach die Umfrage-Deaktivierung testen, da diese den Container nutzt.

Betroffene Dateien:

Relevante Commits:

A4: Statistikexport als XLSX und entfernte Composer-Pakete

Sicherheitsrelevanz
Keine
Handlungsdruck
Mittel
Bruchverhalten
Fehler zur Laufzeit
Betroffen
Administratoren, Integratoren, Plugin-Entwickler

Hintergrund: Der Statistikexport erzeugte bisher über eine nicht mehr gepflegte PEAR-Bibliothek das binäre XLS-Format. Das Release entfernt diese Bibliothek samt ihrer OLE-Abhängigkeit sowie ein nicht mehr gepflegtes Testdaten-Paket aus den Abhängigkeiten, nimmt stattdessen eine Tabellenkalkulations-Bibliothek auf und legt drei Kompatibilitätsklassen an, die die vom Statistikcode genutzte Teilmenge der alten Schnittstelle nachbilden. Die zugehörige Konsolenanwendung zum Einspielen von Testdaten wurde ersatzlos gelöscht.

Konsequenz: Statistikexporte werden künftig als XLSX geliefert, sowohl im Download als auch bei der Ablage im temporären Verzeichnis. Nachgelagerte Verarbeitungsketten, die eine Datei mit der Endung .xls erwarten oder den Inhalt als binäres XLS parsen, schlagen beim ersten Lauf sichtbar fehl. Der Aufruf zum Setzen des temporären Verzeichnisses entfällt; Installationen, die sich für die Zwischenablage großer Exporte auf ein eigens gesetztes Verzeichnis verlassen haben, sollten den Export unter ihren Rechte- und open_basedir-Bedingungen erneut prüfen. Für Eigenbauer entfällt die Konsolenanwendung zum Befüllen einer Testdatenbank; Skripte, die sie aufrufen, brechen beim Start ab.

Vorher / Nachher:

// Vorher (application/helpers/admin/statistics_helper.php)
    $sFileName = $sTempDir . '/statistic-survey' . $surveyid . '.xls';
    $this->workbook = new Spreadsheet_Excel_Writer($sFileName);
} else {
    $this->workbook = new Spreadsheet_Excel_Writer();
}
$this->workbook->setVersion(8);
// Nachher
    $sFileName = $sTempDir . '/statistic-survey' . $surveyid . '.xlsx';
    $this->workbook = new \LimeSurvey\Libraries\Spreadsheet\ExcelWorkbookWriter($sFileName);
} else {
    $this->workbook = new \LimeSurvey\Libraries\Spreadsheet\ExcelWorkbookWriter();
}

Konfiguration: Die Änderung verschiebt Einträge in composer.json. Wer aus den Paketquellen baut, benötigt dort die neu aufgenommene Tabellenkalkulations-Bibliothek; die beiden PEAR-Einträge und der Testdaten-Seeder entfallen. Fehlt der neue Eintrag im eigenen Build, endet der Statistikexport mit einem Fehler über eine nicht gefundene Klasse.

composer.json, vorher:

"pear/ole": "1.*@dev",
"pear/spreadsheet_excel_writer": "^0.9.7",
"tebazil/yii1-db-seeder": "^0.0.0",

composer.json, nachher:

"phpoffice/phpspreadsheet": "^5.8"

Neuer Bezugswert: Die Dateiendung des Statistikexports lautet künftig .xlsx, der Download-Name wird unverändert aus der Umfrage-ID gebildet. Verarbeitungsketten müssen die Endung und den MIME-Typ des Open-XML-Formats erwarten; der Klassenkonstante des neuen Schreibers ist der Typ application/vnd.openxmlformats-officedocument.spreadsheetml.sheethinterlegt.

Nach dem Update testen: Für eine Umfrage mit Antworten den Statistikexport im Format Excel einmal als Download und einmal als Dateiablage auslösen, die erzeugte Datei in einer Tabellenkalkulation öffnen und Umlaute sowie die Prozentformatierung prüfen. Anschließend die eigene Weiterverarbeitung mit der neuen Datei durchlaufen lassen.

Betroffene Dateien:application/helpers/admin/statistics_helper.php, application/helpers/userstatistics_helper.php, application/libraries/Spreadsheet/ExcelWorkbookWriter.php, application/commands/DbSeederCommand.php (entfernt), composer.json

Relevante Commits: eb07711345

Sammel-Commit eb07711345; umfasst die 2 vorstehenden Einträge.

A5: XSS im Bestätigungsdialog der Benutzeraktivierung

Sicherheitsrelevanz
Mittel
Handlungsdruck
Niedrig
Bruchverhalten
Kein Bruch
Betroffen
Administratoren, Integratoren

Hintergrund: Der Bestätigungsdialog zum Aktivieren und Deaktivieren eines Benutzerkontos übernahm den Parameter action ungeprüft aus der Anfrage und schrieb ihn ohne Maskierung in ein verstecktes Formularfeld. Das Release begrenzt den Parameter in beiden beteiligten Aktionen auf die zwei bekannten Werte, maskiert ihn in der Ausgabe und beantwortet abweichende Werte in der ausführenden Aktion mit dem Statuscode 400.

Konsequenz: Ein präparierter Link auf den Dialog kann keinen Code mehr in die Seite einschleusen. Die Ausnutzung setzte einen angemeldeten Benutzer mit Zugriff auf die Benutzerverwaltung voraus, wodurch der Kreis möglicher Ziele begrenzt bleibt. Für Integrationen, die die ausführende Aktion direkt ansprechen, ändert sich das Verhalten: Ein fehlender Parameter wird als Deaktivierung ausgelegt, ein abweichender Wert führt jetzt zu einem Fehler statt zu einer stillen Verarbeitung.

Vorher / Nachher:

// Vorher (application/controllers/UserManagementController.php)
$userId = sanitize_int(Yii::app()->request->getParam('userid'));
$action = Yii::app()->request->getParam('action');
// Nachher
$userId = sanitize_int(Yii::app()->request->getParam('userid'));
$action = Yii::app()->request->getParam('action', 'deactivate');
if (!in_array($action, ['activate', 'deactivate'], true)) {
    throw new CHttpException(400, gT("Invalid action"));
}
// Vorher (application/views/userManagement/partial/confirmuseractivation.php)
<input type="hidden" name="action" value="<?= $action ?>" />
// Nachher
<input type="hidden" name="action" value="<?= CHtml::encode($action) ?>" />

Nach dem Update testen: In der Benutzerverwaltung ein Konto deaktivieren und wieder aktivieren und prüfen, ob der Dialog in beiden Richtungen den korrekten Text zeigt. Anschließend den Dialog mit einem abweichenden Wert im Parameter
action aufrufen und kontrollieren, ob die Seite den Deaktivierungstext zeigt und der abgesendete Vorgang mit
Statuscode 400 endet.

Betroffene Dateien: application/controllers/UserManagementController.php, application/views/userManagement/partial/confirmuseractivation.php

Relevante Commits: 5964f6ca7f

CVE / Advisory: Der Commit-Betreff kennzeichnet die Änderung ausdrücklich als [security] und führt die interne
Kennung #LE-828 sowie die Pull-Request-Nummer 5148. Eine CVE-Kennung oder ein verlinktes Advisory ist im Repository
nicht auffindbar.

A6: Umbenannte Modellmethoden und geänderte Fragethemen-Konvertierung

Sicherheitsrelevanz
Keine
Handlungsdruck
Hoch
Bruchverhalten
Fehler zur Laufzeit
Betroffen
Plugin-Entwickler, Theme-Entwickler, Integratoren

Hintergrund: Zwei öffentliche Methoden von Kernmodellen wurden umbenannt. Die statische Konvertierungsmethode für Fragethemen trug einen Namen, der auf zwei konkrete Hauptversionen verwies, obwohl sie Themen beliebiger älterer Stände verarbeitet; sie heißt jetzt neutral. Die Zählmethode für unvollständige Antworten folgt der geänderten Bezeichnung in der Oberfläche. Im selben Zug wurde die Kompatibilitätslogik der Konvertierung umgeschrieben: Statt eine vorhandene Versionsangabe zu überschreiben, wird ein Kompatibilitätsblock nur noch angelegt, wenn keiner vorhanden ist. Zusätzlich wird ein doppelt vorhandener Attributblock jetzt entfernt statt umbenannt.

Konsequenz: Erweiterungen, die die alten Methodennamen aufrufen, brechen beim ersten Aufruf mit einem Fehler über eine nicht vorhandene Methode ab. Betroffen sind vor allem eigene Importwerkzeuge für Fragethemen und Übersichtsseiten, die Antwortzahlen selbst zusammenstellen. Beim Import eines Fragethemas bleibt eine im Paket hinterlegte Kompatibilitätsangabe künftig erhalten, statt auf einen festen Wert gesetzt zu werden — Themen, die sich bisher auf die automatische Angleichung verlassen haben, werden nun mit ihrer eigenen Angabe geführt. Vermutung: Solche Themen können dadurch in der Übersicht als nicht kompatibel erscheinen; die Annahme stützt sich darauf, dass die Konvertierung eine vorhandene Angabe nicht mehr überschreibt, nicht auf eine im Diff sichtbare Prüfroutine.

Vorher / Nachher:

// Vorher (application/models/QuestionTheme.php)
public static function convertLS3toLS5($sXMLDirectoryPath)
// Nachher
public static function convertLegacyQuestionTheme($sXMLDirectoryPath)
// Vorher (application/models/Survey.php)
public function getCountPartialAnswers()
// Nachher
public function getCountIncompleteAnswers()
// Vorher (application/models/QuestionTheme.php)
// set compatibility version
if (
    $oThemeConfig->compatibility->version
    && count($oThemeConfig->compatibility->version) > 1
) {
    ...
} else {
    $compatibility = $oThemeConfig->addChild('compatibility');
    $compatibility->addChild('version');
    $oThemeConfig->compatibility->version = '5.0';
}
// Nachher
// Only add a <compatibility> block if none exists at all.
if (!isset($oThemeConfig->compatibility)) {
    $oThemeConfig->addChild('compatibility')->addChild('version', '5.0');
}

Neuer Bezugswert: Die Anzahl unvollständiger Antworten wird künftig über getCountIncompleteAnswers bezogen, die Konvertierung eines Fragethemas über convertLegacyQuestionTheme. Ob die alten Namen anderweitig weiterhin erreichbar sind, ist im Diff nicht erkennbar und bleibt offen.

Nach dem Update testen: Ein eigenes Fragethema als ZIP-Paket importieren und in der Themenübersicht die ausgewiesene Kompatibilität mit der im Paket hinterlegten Angabe vergleichen. Anschließend die Umfrageliste öffnen und die Spalte für unvollständige Antworten gegen eine Zählung in der Antworttabelle prüfen. Eigene Erweiterungen auf Vorkommen der beiden alten Methodennamen durchsuchen.

Betroffene Dateien: application/models/QuestionTheme.php, application/helpers/update/updates/Update_425.php, application/models/Survey.php, application/models/SurveyLight.php

Relevante Commits: d4e7399441, 5a9c1ee72c

A7: Schreibgeschützte Fragenattribute werden serverseitig erzwungen

Sicherheitsrelevanz
Niedrig
Handlungsdruck
Mittel
Bruchverhalten
Stiller Fehler
Betroffen
Administratoren, Plugin-Entwickler

Hintergrund: Fragenattribute können als dauerhaft schreibgeschützt oder als schreibgeschützt bei aktiver Umfrage gekennzeichnet sein. Diese Kennzeichnung wirkte bislang nur auf die Darstellung im Einstellungsdialog; übermittelte Werte wurden ungeprüft gespeichert. Das Release wertet die Kennzeichnung beim Speichern aus und überspringt betroffene Attribute, wenn die Umfrage aktiv ist. Zusätzlich reicht das Einstellungs-Widget den Sperrzustand an sein Layout durch.

Konsequenz: Bei aktiver Umfrage werden Änderungen an geschützten Attributen nicht mehr übernommen. Das betrifft unmittelbar die maximale Spaltenzahl der Rangfolgefrage, deren Wert die Struktur der Antworttabelle bestimmt. Erweiterungen und Skripte, die Fragenattribute über den Aggregatdienst setzen, erhalten für solche Attribute keine Fehlermeldung — der Wert wird stillschweigend verworfen. Die Sperre greift nur, wenn das Attribut in den Attributdefinitionen entsprechend gekennzeichnet ist; eigene Attribute ohne diese Kennzeichnung bleiben unverändert schreibbar.

Vorher / Nachher:

// Vorher (application/models/services/QuestionAggregateService/AttributesService.php)
foreach ($dataSet as $attributeKey => $attributeValue) {
  if (
      !isset($attributeValue) ||
      in_array($attributeKey, ['qid', 'debug', 'tempId'])
  ) {
      continue;
  }
// Nachher
foreach ($dataSet as $attributeKey => $attributeValue) {
    if (
        !isset($attributeValue) ||
        in_array($attributeKey, ['qid', 'debug', 'tempId']) ||
        isset($readOnlyAttributes[$attributeKey])
    ) {
        continue;
    }

Nach dem Update testen: Bei einer aktiven Umfrage die maximale Spaltenzahl einer Rangfolgefrage im Einstellungsdialog aufrufen und prüfen, ob das Feld gesperrt ist. Anschließend denselben Wert über die eigene Automatisierung setzen und danach den gespeicherten Stand auslesen, um zu bestätigen, dass der alte Wert erhalten bleibt. Dieselbe Prüfung bei einer inaktiven Umfrage wiederholen; dort muss der Wert weiterhin änderbar sein.

Betroffene Dateien: application/models/services/QuestionAggregateService/AttributesService.php, application/extensions/AdvancedSettingWidget/AdvancedSettingWidget.php, application/helpers/questionHelper.php

Relevante Commits: df0134b5d9

A8: Rasteransichten mit seitenübergreifender Auswahl

Sicherheitsrelevanz
Keine
Handlungsdruck
Mittel
Bruchverhalten
Stiller Fehler
Betroffen
Plugin-Entwickler, Theme-Entwickler

Hintergrund: Die Rasteransicht des Administrationsbereichs konnte Auswahlkästchen bisher nur innerhalb einer Seite auswerten. Das Release registriert für jede Instanz ein neues Skript zur seitenübergreifenden Auswahl, ruft dessen Wiederherstellungsfunktion in jedem Nachlade-Vorgang auf und hängt der ersten Spalte automatisch eine Klasse an, sofern es sich um eine Auswahlspalte handelt. Zusätzlich kommt eine neue Eigenschaft zur Steuerung der Auswahlleiste hinzu sowie ein Widget für eine schwebende Aktionsleiste mit eigenen Stilregeln im Administrations-Theme.

Konsequenz: Erweiterungen, die die Rasteransicht mit einer eigenen Auswahlspalte verwenden, erhalten ohne Zutun eine zusätzliche Klasse an den Kästchen der ersten Spalte und ein zusätzliches Skript im Seitenkopf. Eigene JavaScript-Logik, die dieselben Kästchen nach dem Nachladen selbst zurücksetzt, kann mit der neuen Wiederherstellung um denselben Zustand konkurrieren; der Fehler zeigt sich als scheinbar zufällig wiederkehrende Auswahl, ohne dass eine Meldung erscheint. Wer die Auswahlleiste unterhalb des Rasters nicht wünscht, kann sie über die neue Eigenschaft abschalten. Für Raster, die ohne Nachladen betrieben werden, entsteht kein Rückruf zur Wiederherstellung; dort bleiben Skriptregistrierung und Klassenzuweisung die einzigen Auswirkungen.

Vorher / Nachher:

// Neu (application/extensions/admin/grid/CLSGridView.php)
/**
 * Whether to render the cross-pagination selection bar below the grid.
 * Set to false for grids that use the FloatingActionsWidget to show the count in the floating bar.
 * @var bool
 */
public $showSelectionBar = true;
// Neu (application/extensions/admin/grid/CLSGridView.php)
// Add massiveActionsCheckbox class to the first column if it is a CCheckBoxColumn
$firstColumn = reset($this->columns);
if ($firstColumn instanceof CCheckBoxColumn) {
    $existing = isset($firstColumn->checkBoxHtmlOptions['class']) ? $firstColumn->checkBoxHtmlOptions['class'] . ' ' : '';
    $firstColumn->checkBoxHtmlOptions['class'] = $existing . 'massiveActionsCheckbox';
}

Nach dem Update testen: In jeder von einer Erweiterung bereitgestellten Rasteransicht mit Auswahlspalte mehrere Einträge markieren, eine Seite weiterblättern, weitere Einträge markieren und zurückblättern; prüfen, ob die ursprüngliche Auswahl unverändert erhalten ist und keine Einträge zusätzlich markiert erscheinen. Anschließend eine Massenaktion auslösen und die Zahl der verarbeiteten Datensätze gegen die Auswahl abgleichen.

Betroffene Dateien: application/extensions/admin/grid/CLSGridView.php, application/extensions/admin/grid/assets/gridSelection.js, application/extensions/admin/grid/FloatingActionsWidget, assets/admin_themes/Sea_Green/tables/tables.scss

Relevante Commits: 7911e15fe8, f55ce22121

Weitere relevante Änderungen

Neuer Frageeditor umfassend überarbeitet
Survey Runtime · Kein Bruch · Administratoren, Plugin-Entwickler
Rund ein Drittel der Commits überarbeitet den React-Editor in Rangfolgedarstellung, Bedingungsdesigner, Antwortansicht, Vorschau und Komponentenzuständen, ohne erkennbare Änderung der serverseitigen Schnittstellen. Commit nicht eindeutig zuordenbar.

Zusätzliche Plugin-Slots im Editor
Plugin-Kompatibilität · Kein Bruch · Plugin-Entwickler
Der Editor stellt zwei weitere Einhängepunkte bereit, über die Erweiterungen eigene Inhalte im oberen Bereich und im Layoutrahmen platzieren können. (ed1fdb08d9)

E-Mail-Spalte im Update 706 ergänzt
Datenbank · Kein Bruch · Administratoren
Der Migrationsschritt 706 passt die Länge der E-Mail-Spalte an, bevor er den eindeutigen Index anlegt, und greift nur für Installationen unterhalb dieser Datenbankversion. (7a29276ec1)

// Neu (application/helpers/update/updates/Update_706.php)
alterColumn('{{users}}', 'email', "string(192)");

Teilnehmertabelle wird bei Bedarf angelegt
Datenbank · Kein Bruch · Administratoren
Der Teilnehmerbereich einer Umfrage lässt sich jetzt öffnen, bevor die zugehörige Tabelle existiert; sie wird beim ersten Hinzufügen von Teilnehmern erzeugt. (fe68a7b3ae)

Antworttabelle nach Vorschau korrekt aufgebaut
Datenbank · Kein Bruch · Administratoren
Vor dem Aufbau der Antworttabelle wird der Sitzungszwischenspeicher einer vorangegangenen Vorschau verworfen, sodass die Aktivierung nicht mehr auf veralteten Felddaten aufsetzt. (db5c7bb13b)

Statistikexport wieder funktionsfähig
Survey Runtime · Kein Bruch · Administratoren
Der Statistikexport greift jetzt auf den geprüften Feldnamen der Antworttabelle zu statt auf einen um den Fragetyp verlängerten Schlüssel. (ecfa647bd6)

Statistikfilter für Mehrfachauswahl korrigiert
Survey Runtime · Kein Bruch · Administratoren
Filter auf Mehrfachauswahlfragen in der Statistik führen nicht mehr zu einem Fehler. (7a9d5a9d6c)

Downloadnamen für HTML- und JSON-Export gesetzt
Survey Runtime · Kein Bruch · Integratoren
Der Antwortexport in den Formaten HTML und JSON sendet nun einen Dateinamen im Antwort-Header, sodass Aufrufe als Download statt als Anzeige behandelt werden. (27d85cbe23)

Abfrage-Cache vor dem Speichern zurückgesetzt
RemoteControl API · Kein Bruch · API-Nutzer, Administratoren
Vor dem Schreiben von Umfrageeinstellungen wird der Modell-Cache verworfen, damit schreibgeschützte Einstellungen nicht mit veralteten Werten überschrieben werden. (8e9cbb2d00)

Twig-Funktion für Expression-Manager-Ausgabe erweitert
Themes und Rendering · Kein Bruch · Theme-Entwickler
Die für Twig freigegebene Funktion zur Auswertung von Ausdrücken nimmt jetzt optionale Ersetzungswerte entgegen und räumt sie nach der Auswertung wieder ab. (8342d79b74)

Ausgeblendete Unterfragen in mobiler Ansicht korrigiert
Themes und Rendering · Kein Bruch · Theme-Entwickler
Die Regel für die tabellenlose Mobilansicht nimmt ausgeblendete Zeilen aus, sodass durch Bedingungen versteckte Unterfragen nicht mehr sichtbar werden. (f033af2fb8)

Andere-Option im Bootstrap-Buttons-Fragethema korrigiert
Themes und Rendering · Kein Bruch · Theme-Entwickler
Das Fragethema übergibt der zugehörigen Skriptlogik jetzt den passenden Feldnamen, sodass das Eingabefeld der eingebauten Andere-Option wieder erscheint. (c8fc69f0ef)

Zuordnung nach Bereich

BereichVollständig beschriebenWeitere Einträge
SicherheitA5
DatenbankA1ja
RemoteControl APIA1ja
Survey RuntimeA1, A2, A7ja
Themes und RenderingA2, A6, A8ja
Plugin-KompatibilitätA3, A4, A6, A7, A8ja
Performancekeine

Nicht betroffene Bereiche

  • Die Ereignisschnittstelle für Erweiterungen zeigt keine Änderung: application/libraries/PluginManager/PluginEvent.php und application/libraries/PluginManager/PluginManager.php treten im Diff nicht auf.
  • Der Einstiegspunkt und die Routendefinition bleiben unverändert: Weder index.php noch application/config/routes.php sind Teil des Diffs.
  • Die ausgelieferten Vorgabewerte der Anwendungskonfiguration bleiben stehen: application/config/config-defaults.php erscheint nicht im Diff.
  • Das Berechtigungsmodell bleibt unangetastet: application/models/Permission.php ist im Diff nicht enthalten.
  • Der zitierte Migrationscode von Update 709 spricht ausschließlich die Antworttabellen aktiver Umfragen und die Spalte type der Fragentabelle an; weitere Struktur-, Index- oder Constraint-Eingriffe sind in diesem Zitat nicht erkennbar.

Empfehlung

Administratoren

Vor dem Update: Eine vollständige Datenbanksicherung anlegen und ausdrücklich prüfen, dass sie die Antworttabellen aktiver Umfragen enthält (A1). Die eigenen Umfragen auf Rangfolgefragen durchsuchen und für die betroffenen Umfragen den Spaltenbestand notieren (A1). Nachgelagerte Auswertungen und Berichtsstrecken auf Zugriffe mit den bisherigen Rangfolge-Spaltennamen und auf die Erwartung einer Statistikdatei im alten Format prüfen (A1, A4). Das Update zuerst auf einer Kopie der Produktivdatenbank durchführen.

Unmittelbar nach dem Update: Die interne Datenbankversion in der Systeminformation gegen den Wert 709 abgleichen (A1). Eine aktive Umfrage mit Rangfolgefrage exportieren und den Datensatz gegen die Sicherung vergleichen (A1). Den Statistikexport einmal auslösen und die erzeugte Datei öffnen (A4). Den Zugangscode-Konflikt in zwei Browser-Tabs nachstellen und den Neustart-Link prüfen (A2). In der Benutzerverwaltung eine Aktivierung und eine Deaktivierung durchführen (A5). Bei aktiven Umfragen kontrollieren, dass die maximale Spaltenzahl der Rangfolgefrage gesperrt ist (A7).

Rollback: Ein Rückgang auf 7.0.5 ist nach gelaufener Migration nicht ohne Datenverlust möglich: Das Zitat in A1 belegt, dass die Ursprungsspalten der Rangfolgefragen mit dropColumn entfernt werden, und der Migrationscode enthält keinen erkennbaren Rückweg. Ein Rollback erfordert daher das Einspielen der vor dem Update angelegten Datenbanksicherung zusammen mit dem alten Dateistand. Ob die Migration bei einem zweiten Lauf gefahrlos wiederholbar ist, ist nicht bestimmbar und vor jedem erneuten Versuch in einer Testumgebung zu klären. Für die Abhängigkeitsanhebungen aus A3 und A4 genügt bei Eigenbau das Zurücksetzen von composer.json und ein erneuter Lauf des Abhängigkeitsmanagers; Konfigurationsdateien legt das Update nach dem vorliegenden Diff nicht an.

Plugin-Entwickler

Zuerst den eigenen Code auf Docblock-Annotationen für die Injektion durchsuchen und auf PHP-Attribute umstellen (A3). Danach die beiden umbenannten Modellmethoden ersetzen (A6). Anschließend Zugriffe auf die bisherigen Rangfolge-Spalten in eigenen Abfragen, Exporten und Ereignisbehandlungen auf die neue JSON-Spalte umstellen (A1). Eigene Fragenattribute darauf prüfen, ob sie als schreibgeschützt gekennzeichnet sind und ob der eigene Speicherpfad damit umgehen kann (A7). Zuletzt eigene Rasteransichten mit Auswahlspalte auf Konflikte mit der neuen Auswahlwiederherstellung testen (A8) und, wer selbst baut, den Wegfall der Tabellenkalkulations-Altbibliothek berücksichtigen (A4).

Theme-Entwickler

Zuerst alle eigenen Umfrage-Themes prüfen, die layout_errors.twig überschreiben, und den Block für das FeldaError.URL nachziehen (A2). Danach eigene Fragethemen-Pakete mit dem Importweg testen und die ausgewiesene Kompatibilität kontrollieren (A6). Wer die Stylesheets des Administrationsbereichs selbst aus den Quellen baut, übernimmt die neuen Regeln für die schwebende Aktionsleiste und die Rasterauswahl (A8). Ergänzend die in Weitere relevante Änderungen genannten Anpassungen an der tabellenlosen Mobilansicht und am Bootstrap-Buttons-Fragethema in eigene Ableitungen übernehmen.

Integratoren

Zuerst alle Strecken identifizieren, die Antwortdaten direkt aus der Datenbank oder aus Exportdateien lesen, und die Behandlung von Rangfolgefragen auf das JSON-Format umstellen (A1). Danach die Weiterverarbeitung des Statistikexports auf das neue Dateiformat anpassen (A4). Wiedereinstiegslinks mit Zugangscodes darauf prüfen, ob sie den bisherigen automatischen Neustart voraussetzen (A2). Aufrufe der Benutzeraktivierung auf zulässige Werte des Aktionsparameters prüfen, da abweichende Werte jetzt mit Statuscode 400 beantwortet werden (A5). Eigene Importwerkzeuge für Fragethemen auf die umbenannte Konvertierungsmethode umstellen (A6).

API-Nutzer

Zuerst die Rückgabe der Antwortabfragen für Umfragen mit Rangfolgefragen erneut auslesen und die Feldstruktur gegen die bisherige Erwartung abgleichen (A1). Verarbeitungslogik, die je Rang ein eigenes Feld erwartet, auf das zusammengefasste Feld umstellen. Ergänzend das in Weitere relevante Änderungen beschriebene Zurücksetzen des Abfrage-Caches beim Schreiben von Umfrageeinstellungen berücksichtigen: Rückgaben nach einem Schreibvorgang spiegeln nun den tatsächlich gespeicherten Stand.