realURL: optimierte Multi-Domain-Konfiguration

Ausgangssituation

In einem Projekt waren in einer TYPO3-Instanz über den Seitenbaum mehrere Marken in verschiedenen Ländern mit jeweils eigenen (Teil-)Seitenbaum abgebildet. Die einzelnen Websites waren inhaltlich-strukturell sehr ähnlich, und es waren viele spezifische Plugins im Einsatz. Insgesamt entstand so für die rund 100 Einstiegseiten eine (via realURL-Autoconfiguration erzeugte) rund 4,5 MB große Konfiguration. Die war uns ein Dorn im Auge.

Ansätze

1. Nutzung der _DEFAULT-Konfiguration

Zunächst mag man denken: „die Autokonfiguration ist hier ungeeignet, manuell lässt sich das kürzer fassen“. In der Tat, die Autokonfiguration schreibt die gesamte Konfiguration pro Domain einmal in die Datei. Dies lässt sich kürzer schreiben in der Art:

$TYPO3_CONF_VARS['EXTCONF']['realurl']['example.com'] = $TYPO3_CONF_VARS['EXTCONF']['realurl']['_DEFAULT'];
$TYPO3_CONF_VARS['EXTCONF']['realurl']['example.com'] ['pagePath']['rootpage_id'] = 1234;

Unterm Strich gewinnt man hierdurch aber nicht viel: die erzeugte Datei ist nun zwar kleiner, dafür wird das Array via PHP wieder vervielfacht – und am Ende ist das EXTCONF-realurl-Array wieder genauso groß wie ursprünglich.

2. Splitten der Konfiguration

Warum soll eigentlich für jeden Aufruf die gesamte realURL-Konfiguration aller Domains im Seitenbaum geladen werden, um dann doch nur einen Teil (den der konkreten Domain) zu nutzen? In unserem Szenario werden rund 99% geladen, aber nie genutzt, weil für andere Domains bestimmt. Es liegt also nahe, die Konfiguration zu splitten, und nur den relevanten Teil zu laden. Um hierbei dennoch flexibel zu bleiben und die Vorteile der auto-configuration von realURL nutzen zu können, nutzen wir einen Scheduler-Task zum Splitten:

    public function execute() {
            // if realurl is not loaded, we have nothing to do.
        if (t3lib_extMgm::isLoaded('realurl') === FALSE) {
            return FALSE;
        }
 
        define('TX_REALURL_AUTOCONF_FILE', 'typo3conf/realurl_autoconf.php');
        if (@is_file(PATH_site . TX_REALURL_AUTOCONF_FILE) === FALSE) {
            /** @var tx_realurl_autoconfgen $autoconfgen */
            $autoconfgen = t3lib_div::makeInstance('tx_realurl_autoconfgen');
            $autoconfgen->generateConfiguration();
        }
        if (!isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl'])) {
            @include_once(PATH_site . TX_REALURL_AUTOCONF_FILE);
        }
 
            // If there's no configuration, it is not necessary to split anything.
        if (!is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl'])) {
            return TRUE;
        }
        $directory = 'typo3conf/realurl/';
        $baseDir = PATH_site . $directory;
        if (@is_dir($baseDir) === FALSE) {
            t3lib_div::mkdir_deep(PATH_site, $directory);
            t3lib_div::fixPermissions($baseDir); // Change the permissions of the file
        }
 
        $bytesWritten = 0;
        $nl  = "\n";
        $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_domain', 'hidden=0 AND redirectTo=""', '', '', 1000);
        if ($res) {
            while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
                if ($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl'][$row['domainName']]) {
                    $phpCode = '<?php' . $nl;
                    $phpCode .= '$TYPO3_CONF_VARS[\'EXTCONF\'][\'realurl\'] = array();' . $nl;
                    $phpCode .= '$TYPO3_CONF_VARS[\'EXTCONF\'][\'realurl\'][\'' . $row['domainName'] . '\'] = unserialize(\'' . str_replace('\'', '\\\'', serialize($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl'][$row['domainName']])) . '\');' . $nl;
                    $phpCode .= '?>';
                        // write
                    $path = PATH_site . $directory . $row['domainName']. '.php';
                    $bytesWritten += file_put_contents($path, $phpCode);
                }
            }
            $GLOBALS['TYPO3_DB']->sql_free_result($res);
        }
 
            // Delete unnecessary autoconfig file
        if ($bytesWritten > 0) {
            if (@is_file(PATH_site . TX_REALURL_AUTOCONF_FILE)) {
                if (unlink(PATH_site . TX_REALURL_AUTOCONF_FILE)) {
                    return TRUE;
                }
            }
        }
 
        return ($bytesWritten > 0 ? TRUE : FALSE);
    }

Als Ergebnis erhalten wir zig ca. 12kB große Dateien. Diese müssen jetzt nur noch passend eingebunden werden. Hierzu reicht ein 8-Zeiler in der localconf.php (Ja, ist noch ein TYPO3 4.5 😉 ):

$currentHost = t3lib_div::getIndpEnv('TYPO3_HOST_ONLY');
// via Task erzeugte realurl-Konfig EINER Domain laden
if (@is_file(PATH_site . 'typo3conf/realurl/' . $currentHost . '.php') === TRUE) {
    include_once(PATH_site . 'typo3conf/realurl/' . $currentHost . '.php');
} else if (@is_file(PATH_site . 'typo3conf/realurl/_DEFAULT.php') === TRUE) {
    include_once(PATH_site . 'typo3conf/realurl/_DEFAULT.php');
}
unset($currentHost);

Somit wird nun pro Aufruf kein 4,5MB großes Array mehr eingelsen, sondern nur noch 12kB. Bei unserem Projekt konnten wir die Memory-Auslastung des Server durch diesen Eingriff spürbar senken. Ob es die beste Lösung ist? – Keine Ahnung.

 

Über andere Ideen und Lösungen würde ich mich freuen. Wie geht ihr mit großen (aber flexiblen) Multidomain_Seitenbäumen samt realURL um?

Update

Bei der Einbindung in die Konfiguration muss noch ein Test durchgeführt werden, ob wir überhaupt im Frontend sind. Dies hat den Hintergrund, dass ansonsten dem Task nur die _DEFAULT-Konfiguration zur Verfügung steht:

$currentHost = t3lib_div::getIndpEnv('TYPO3_HOST_ONLY');
// via Task erzeugte realurl-Konfig EINER Domain laden
if (TYPO3_MODE == 'FE') {
    if( @is_file(PATH_site . 'typo3conf/realurl/' . $currentHost . '.php') === TRUE) {
        include_once(PATH_site . 'typo3conf/realurl/' . $currentHost . '.php');
    } else if (@is_file(PATH_site . 'typo3conf/realurl/_DEFAULT.php') === TRUE) {
        include_once(PATH_site . 'typo3conf/realurl/_DEFAULT.php');
    }
}
unset($currentHost);

Schreibe einen Kommentar