TYPO3_CONTEXT ohne .htaccess

Auf meinem Server, auf dem ich i.d.R. eine Staging-Version zum Testen und Zeigen hochlade, verbietet der Provider wohl aus Sicherheitsgründen das Setzen von Umgebungsvariablen mithilfe der .htaccess-Datei. Zudem ist es den CLI-Scripten bin/typo3 oder bin/typo3cms ziemlich egal, was in irgendeiner .htaccess steht. Um trotzdem automatisiert den Context zu setzen, zeige ich hier einen Weg über die Abfrage des Document-Roots.

Folgende Ordner-Struktur lege ich zugrunde. Diese stammt aus einer Typo3-Installation, die mit Hilfe von composer erstellt wurde. Für die normale .tar.gz-Installation bräuchte man dann eigentlich nur den Pfad public anpassen - ok, das CLI Script ist dann auch an einem anderen Ort zu finden:
typo3/sysext/core/bin/typo3.
Ob es Helmut Hummels typo3cms CLI auch für ohne composer gibt, weiß ich an dieser Stelle gerade nicht.
Nachtrag: gibt es: https://github.com/TYPO3-Console/TYPO3-Console.

bin/
- development/
- - typo3
- - typo3cms
- production/
- - typo3
- - typo3cms
- production_staging/
- - typo3
- - typo3cms
public/
- index.php
- typo3/
- - index.php
- - install.php
- typo3conf/
- - AdditionalConfiguration.php
- - DevelopmentConfiguration.php
- - Production_StagingConfiguration.php
- - ProductionConfiguration.php
vendor/
- bin/
- - typo3
- - typo3cms
TYPO3_CONTEXT.php

Zuerst die zentrale Datei, die den Context für HTTP setzt:

TYPO3_CONTEXT.php

<?php
// sets TYPO3_CONTEXT in relation of document root
// include this file at the top of all files where context should be set:
// public/index.php
// public/typo3/index.php
// public/typo3/install.php

switch ($_SERVER["DOCUMENT_ROOT"]) {
    case "/var/www/public_html/public":
        putenv('TYPO3_CONTEXT=Production');
        break;
    case "/var/www/vhost/dev.server.com/public_html":
        putenv('TYPO3_CONTEXT=Production/Staging');
        break;
    case "/Users/me/Webserver/typo3/project.local":
        putenv('TYPO3_CONTEXT=Development');
        break;
}

Includes

Diese muss dann einfach in allen zentralen Dateien eingebunden werden:

Datei: public/index.php

<?php
require dirname(__DIR__) . '/TYPO3_CONTEXT.php';
// [...]

Datei: public/typo3/index.php

<?php
require dirname(dirname(__DIR__)) . '/TYPO3_CONTEXT.php';
// [...]

Datei: public/typo3/install.php

<?php
require dirname(dirname(__DIR__)) . '/TYPO3_CONTEXT.php';
// [...]

CLI

Beim CLI (command line interface) gibt es leider kein Document-Root. Hier nutze ich einfach ein paar Wrapper für die eigentlichen Scripte.

Datei: bin/development/typo3

#!/usr/bin/env php
<?php
putenv('TYPO3_CONTEXT=Development');
require dirname(dirname(__DIR__)) . '/vendor/bin/typo3';

Datei: bin/development/typo3cms

#!/usr/bin/env php
<?php
putenv('TYPO3_CONTEXT=Development');
require dirname(dirname(__DIR__)) . '/vendor/bin/typo3cms';

Datei: bin/production/typo3

#!/usr/bin/env php
<?php
putenv('TYPO3_CONTEXT=Production');
require dirname(dirname(__DIR__)) . '/vendor/bin/typo3';

Datei: bin/production/typo3cms

#!/usr/bin/env php
<?php
putenv('TYPO3_CONTEXT=Production');
require dirname(dirname(__DIR__)) . '/vendor/bin/typo3cms';

Datei: bin/production_staging/typo3

#!/usr/bin/env php
<?php
putenv('TYPO3_CONTEXT=Production/Staging');
require dirname(dirname(__DIR__)) . '/vendor/bin/typo3';

Datei: bin/production_staging/typo3cms

#!/usr/bin/env php
<?php
putenv('TYPO3_CONTEXT=Production/Staging');
require dirname(dirname(__DIR__)) . '/vendor/bin/typo3cms';

Anstatt
php vendor/bin/typo3cms database:export > db.sql
ruft man nun z.B.
php bin/development/typo3cms database:export > db.sql
auf.

Auf dem Staging-Server dann entsprechend:
php bin/production_staging/typo3cms database:import < db.sql

Verwenden des TYPO3_CONTEXT in der PHP-Konfiguration

Für jede der Umgebungen kann man nun eine eigene Konfiguration z.B. für die Datenbank setzen:

Datei: public/typo3conf/AdditionalConfiguration.php

<?php
if ( !defined( 'TYPO3_MODE' ) ) {
    die( 'Access denied.' );
}

// get application context
$currentApplicationContext = \TYPO3\CMS\Core\Utility\GeneralUtility::getApplicationContext();

// make visible in backend
$GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] .= ' (' . (string) $currentApplicationContext . ')';

// build file prefix
$currentApplicationContextFilePrefix = str_replace("/", "_", (string) $currentApplicationContext);

// look for configuration file
$contextConfigFile = PATH_site . 'typo3conf/' . $currentApplicationContextFilePrefix . 'Configuration.php';
if (!file_exists($contextConfigFile)) {
    die( "Could not find configuration file: " . $contextConfigFile );
}

// load file
require($contextConfigFile);

In der Datei public/typo3conf/DevelopmentConfiguration.php steht dann z.B. sowas:

<?php
if ( !defined( 'TYPO3_MODE' ) ) {
    die( 'Access denied.' );
}
/**
 * Development environment
 * TYPO3_CONTEXT Development
 */

// GFX
$GLOBALS['TYPO3_CONF_VARS']['GFX']['jpg_quality'] = '80';
$GLOBALS['TYPO3_CONF_VARS']['GFX']['processor'] = 'ImageMagick';
$GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_allowTemporaryMasksAsPng'] = false;
$GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_colorspace'] = 'sRGB';
$GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_effects'] = 1;
$GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_enabled'] = true;
$GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_path'] = '/usr/local/bin/';
$GLOBALS['TYPO3_CONF_VARS']['GFX']['processor_path_lzw'] = '/usr/local/bin/';


// DATABASE
$GLOBALS['TYPO3_CONF_VARS']['DB']['Connections']['Default'] = [
    'charset' => 'utf8mb4',
    'dbname' => 'typo3_project',
    'driver' => 'mysqli',
    'host' => 'localhost',
    'password' => 'top_secret',
    'tableoptions' => [
        'charset' => 'utf8mb4',
        'collate' => 'utf8mb4_unicode_ci',
    ],
    'user' => 'typo3_dev',
];

// MAIL
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport'] = 'smtp';
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_smtp_server'] = 'mailserver.de:465';
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_smtp_encrypt'] = 'ssl';
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_smtp_username'] = 'dev@project.com';
$GLOBALS['TYPO3_CONF_VARS']['MAIL']['transport_smtp_password'] = 'also_top_secret';

In
public/typo3conf/productionConfiguration.php
und
public/typo3conf/Production_StagingConfiguration.php
steht entsprechend deren Konfiguration.

Verwenden des TYPO3_CONTEXT als TypoScript condition

Im TypoScript kann man den Context z.B. dazu nutzen eine BaseURL zu setzen:

config.baseURL = https://project.com/
config.absRefPrefix = auto
[applicationContext=Production/Staging]
config.baseURL = http://dev.server.com/project.com/public/
config.absRefPrefix = http://dev.server.com/project.com/public/
[applicationContext=Development]
config.baseURL = http://project.local:8888/
config.absRefPrefix = http://project.local:8888/
[END]

Verwenden des TYPO3_CONTEXT in der sites-Konfiguration

In der sites-Konfiguration sieht das z.B. so aus:

Datei: config/sites/project/config.yaml

rootPageId: 1
base: 'http://project.com/'
baseVariants:
  -
    base: 'http://project.local:8888/'
    condition: 'applicationContext == "Development"'
  -
    base: 'http://dev.server.com/project.com/public/'
    condition: 'applicationContext == "Production/Staging"'

Diskussionen/Feedback

... geht momentan nur auf Twitter: https://twitter.com/sunixzs/status/1098146748479033344