Bezpečná správa .env, config() vs env() a proč v produkci cachujeme konfiguraci
Proč funkce env() smí být volána výhradně v konfiguračních souborech v config/, jak funguje php artisan config:cache a jak produkční entrypoint spouští optimalizace.
Správa konfigurace: Zlaté pravidlo config() vs env()
Jednou z nejčastějších začátečnických chyb v Laravelu je přímé volání pomocné funkce env() uvnitř Controllerů, Servisních tříd nebo Blade šablon (např. if (env('APP_DEBUG'))).
V produkčním prostředí takový kód povede k fatální chybě nebo nečekanému chování. Proč?
Jak funguje php artisan config:cache (a php artisan optimize)
Během lokálního vývoje Laravel při každém HTTP požadavku parsuje soubor .env pomocí knihovny vlucas/phpdotenv. To je pro vývoj pohodlné, ale na produkčním serveru to zbytečně zpomaluje běh (čtení ze souboru a parsování řetězců při každém requestu).
Proto v produkčním Docker kontejneru v docker/entrypoint.sh automaticky spouštíme:
php artisan optimize
Tento příkaz mimo jiné spustí php artisan config:cache, který:
- Načte všechny soubory z adresáře
config/(app.php,database.php,cache.php...). - Spočítá všechny výrazy
env(...)a dosadí jejich aktuální hodnoty. - Sloučí celou konfiguraci do jediného obřího PHP pole a zapíše jej do souboru
bootstrap/cache/config.php. - Vypne načítání souboru
.env! Proměnné prostředí se již do globálního superglobálního pole$_ENVnenačítají.
[!CAUTION] Jakmile je konfigurace nacachována, jakékoliv volání
env('MOJE_PROMENNA')kdekoliv mimo adresářconfig/vrátí hodnotunull!
Správný postup: Vše přes config(...)
- Definice v souboru v
config/(např.config/app.php):
return [
'name' => env('APP_NAME', 'Anatomie Laravelu 12'),
'env' => env('APP_ENV', 'production'),
'debug' => (bool) env('APP_DEBUG', false),
'key' => env('APP_KEY'),
];
- Čtení v aplikačním kódu (v controlleru, službě, šabloně):
// Správně: funguje v devu i v produkci s nacachovanou konfigurací
$appName = config('app.name');
$isDebug = config('app.debug');
Bezpečnost šifrovacího klíče APP_KEY a rotace klíčů
Proměnná APP_KEY je 32znakový náhodný řetězec generovaný příkazem php artisan key:generate. Slouží k:
- Šifrování všech cookies (uživatel nemůže modifikovat obsah cookies na klientovi).
- Šifrování podepsaných URL adres (Signed URLs).
- Šifrování citlivých údajů přes fasádu
Crypt::encryptString(...).
Všimněte si v config/app.php skvělé funkce moderního Laravelu pro rotaci šifrovacích klíčů:
'key' => env('APP_KEY'),
'previous_keys' => [
...array_filter(
explode(',', (string) env('APP_PREVIOUS_KEYS', ''))
),
],
Když potřebujete z bezpečnostních důvodů změnit produkční klíč, přesunete starý klíč do APP_PREVIOUS_KEYS. Laravel pak šifruje novým klíčem, ale staré existující cookies a tokeny dokáže stále bezchybně dešifrovat bez odhlášení uživatelů!
Orchestrace v docker/entrypoint.sh
V našem Docker kontejneru řídí start aplikace skript docker/entrypoint.sh:
- Zajišťuje správná oprávnění pro
storage/abootstrap/cache/(uživatelwww-data). - Při příznaku
RUN_MIGRATIONS=1vyčká na dostupnost PostgreSQL (php artisan db:monitor). - Spustí migrace
php artisan migrate --force. - Provede
php artisan optimize, čímž zkompiluje konfiguraci, routy i Blade pohledy do OPcache pro maximální rychlost FrankenPHP serveru.
// config/app.php:18-45, 100-108
'name' => env('APP_NAME', 'Laravel'),
'env' => env('APP_ENV', 'production'),
'debug' => (bool) env('APP_DEBUG', false),
'cipher' => 'AES-256-CBC',
'key' => env('APP_KEY'),
'previous_keys' => [
...array_filter(
explode(',', (string) env('APP_PREVIOUS_KEYS', ''))
),
],
// docker/entrypoint.sh:32
php artisan optimize
🎯 Ověření znalostí z lekce
Kvíz otestuje pochopení architektury a reálného kódu probíraného v této lekci.
Co se stane, pokud zavoláte funkci env('MOJE_HODNOTA') uvnitř kontroleru v produkci, kde byl spuštěn příkaz php artisan config:cache?
K čemu slouží pole "previous_keys" v konfiguračním souboru config/app.php?
Jaký je účel příkazu "php artisan optimize" spouštěného v produkčním docker/entrypoint.sh?
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | return [ |
| 6 | |
| 7 | /* |
| 8 | |-------------------------------------------------------------------------- |
| 9 | | Application Name |
| 10 | |-------------------------------------------------------------------------- |
| 11 | | |
| 12 | | This value is the name of your application, which will be used when the |
| 13 | | framework needs to place the application's name in a notification or |
| 14 | | other UI elements where an application name needs to be displayed. |
| 15 | | |
| 16 | */ |
| 17 | |
| 18 | 'name' => env('APP_NAME', 'Laravel'), |
| 19 | |
| 20 | /* |
| 21 | |-------------------------------------------------------------------------- |
| 22 | | Application Environment |
| 23 | |-------------------------------------------------------------------------- |
| 24 | | |
| 25 | | This value determines the "environment" your application is currently |
| 26 | | running in. This may determine how you prefer to configure various |
| 27 | | services the application utilizes. Set this in your ".env" file. |
| 28 | | |
| 29 | */ |
| 30 | |
| 31 | 'env' => env('APP_ENV', 'production'), |
| 32 | |
| 33 | /* |
| 34 | |-------------------------------------------------------------------------- |
| 35 | | Application Debug Mode |
| 36 | |-------------------------------------------------------------------------- |
| 37 | | |
| 38 | | When your application is in debug mode, detailed error messages with |
| 39 | | stack traces will be shown on every error that occurs within your |
| 40 | | application. If disabled, a simple generic error page is shown. |
| 41 | | |
| 42 | */ |
| 43 | |
| 44 | 'debug' => (bool) env('APP_DEBUG', false), |
| 45 | |
| 46 | /* |
| 47 | |-------------------------------------------------------------------------- |
| 48 | | Application URL |
| 49 | |-------------------------------------------------------------------------- |
| 50 | | |
| 51 | | This URL is used by the console to properly generate URLs when using |
| 52 | | the Artisan command line tool. You should set this to the root of |
| 53 | | the application so that it's available within Artisan commands. |
| 54 | | |
| 55 | */ |
| 56 | |
| 57 | 'url' => env('APP_URL', 'http://localhost'), |
| 58 | |
| 59 | /* |
| 60 | |-------------------------------------------------------------------------- |
| 61 | | Application Timezone |
| 62 | |-------------------------------------------------------------------------- |
| 63 | | |
| 64 | | Here you may specify the default timezone for your application, which |
| 65 | | will be used by the PHP date and date-time functions. The timezone |
| 66 | | is set to "UTC" by default as it is suitable for most use cases. |
| 67 | | |
| 68 | */ |
| 69 | |
| 70 | 'timezone' => 'UTC', |
| 71 | |
| 72 | /* |
| 73 | |-------------------------------------------------------------------------- |
| 74 | | Application Locale Configuration |
| 75 | |-------------------------------------------------------------------------- |
| 76 | | |
| 77 | | The application locale determines the default locale that will be used |
| 78 | | by Laravel's translation / localization methods. This option can be |
| 79 | | set to any locale for which you plan to have translation strings. |
| 80 | | |
| 81 | */ |
| 82 | |
| 83 | 'locale' => env('APP_LOCALE', 'en'), |
| 84 | |
| 85 | 'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'), |
| 86 | |
| 87 | 'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'), |
| 88 | |
| 89 | /* |
| 90 | |-------------------------------------------------------------------------- |
| 91 | | Encryption Key |
| 92 | |-------------------------------------------------------------------------- |
| 93 | | |
| 94 | | This key is utilized by Laravel's encryption services and should be set |
| 95 | | to a random, 32 character string to ensure that all encrypted values |
| 96 | | are secure. You should do this prior to deploying the application. |
| 97 | | |
| 98 | */ |
| 99 | |
| 100 | 'cipher' => 'AES-256-CBC', |
| 101 | |
| 102 | 'key' => env('APP_KEY'), |
| 103 | |
| 104 | 'previous_keys' => [ |
| 105 | ...array_filter( |
| 106 | explode(',', (string) env('APP_PREVIOUS_KEYS', '')) |
| 107 | ), |
| 108 | ], |
| 109 | |
| 110 | /* |
| 111 | |-------------------------------------------------------------------------- |
| 112 | | Maintenance Mode Driver |
| 113 | |-------------------------------------------------------------------------- |
| 114 | | |
| 115 | | These configuration options determine the driver used to determine and |
| 116 | | manage Laravel's "maintenance mode" status. The "cache" driver will |
| 117 | | allow maintenance mode to be controlled across multiple machines. |
| 118 | | |
| 119 | | Supported drivers: "file", "cache" |
| 120 | | |
| 121 | */ |
| 122 | |
| 123 | 'maintenance' => [ |
| 124 | 'driver' => env('APP_MAINTENANCE_DRIVER', 'file'), |
| 125 | 'store' => env('APP_MAINTENANCE_STORE', 'database'), |
| 126 | ], |
| 127 | |
| 128 | ]; |
| 129 | |