Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Variables de entorno

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

Abrir config/packages/framework.yaml. No necesitamos estar autentificados para utilizar esta parte de la API de GitHub dedicada al contenido en bruto del usuario:

... line 1
framework:
... lines 3 - 19
http_client:
scoped_clients:
githubContentClient:
base_uri: https://raw.githubusercontent.com
... lines 24 - 30

Pero si accedemos mucho a esta ruta, podríamos llegar a su límite de velocidad, que es bastante bajo para los usuarios anónimos. Así que vamos a autenticar nuestra petición.

Añadir una cabecera de autorización a la petición HTTP

En primer lugar, si estás codificando conmigo, dirígete a "github.com" y crea tu propio token de acceso personal. Una vez hecho esto, abre MixRepository y baja hasta donde hacemos la petición HTTP. Para adjuntar el token de acceso a la petición pasa un tercer argumento, que es un array. Dentro, añade una clave headers fijada en otro array, con una cabecera Authorization asignada a la palabra Token y luego el token de acceso. Empieza utilizando un token falso:

... lines 1 - 13
class MixRepository
{
... lines 16 - 24
public function findAll(): array
{
... lines 27 - 32
return $this->cache->get('mixes_data', function(CacheItemInterface $cacheItem) {
... line 34
$response = $this->githubContentClient->request('GET', '/SymfonyCasts/vinyl-mixes/main/mixes.json', [
'headers' => [
'Authorization' => 'Token ghp_foo_bar',
]
]);
... lines 40 - 41
});
}
}

Puedes saber que esto funciona porque, cuando volvemos a la página y la refrescamos... ¡estalla! Nuestra llamada a la API ahora falla con un 404 porque reconoce que estamos intentando autenticarnos con un token... pero el que hemos pasado es falso.

Ahora añade tu token real. Inténtalo de nuevo y... ¡funciona!

Moviendo el encabezado de autorización a framework.yaml

¡Así que esto es genial! Pero sería mejor si el servicio viniera preconfigurado para establecer automáticamente esta cabecera de autorización... especialmente si queremos utilizar este servicio de Cliente HTTP en varios sitios. ¿Podemos hacerlo? Por supuesto

Copia la línea Token, entra en framework.yaml, y después de base_uri, pasa una clave headers con Authorization ajustada a nuestra cadena larga. En realidad, déjame poner un token falso ahí temporalmente:

... line 1
framework:
... lines 3 - 19
http_client:
scoped_clients:
githubContentClient:
base_uri: https://raw.githubusercontent.com
headers:
Authorization: 'Token ghp_FAKE'
... lines 26 - 32

En MixRepository, elimina ese tercer argumento:

... lines 1 - 13
class MixRepository
{
... lines 16 - 24
public function findAll(): array
{
... lines 27 - 32
return $this->cache->get('mixes_data', function(CacheItemInterface $cacheItem) {
... line 34
$response = $this->githubContentClient->request('GET', '/SymfonyCasts/vinyl-mixes/main/mixes.json');
... lines 36 - 37
});
}
}

Y ahora, cuando probemos esto... ¡genial! Las cosas se rompen, lo que demuestra que estamos enviando esa cabecera... sólo que con el valor equivocado. Si cambiamos a nuestro token real... una vez más... ¡funciona! ¡Genial!

Hola Variables de Entorno

Hasta ahora, esto es sólo una bonita característica del HttpClient. Pero esto también ayuda a poner de manifiesto un problema común. No es... genial tener nuestro sensible token de la API de GitHub codificado en este archivo. Es decir, este archivo va a ser enviado a nuestro repositorio. Quiero a mis compañeros de equipo... pero no los quiero tanto como para compartir mi token de acceso con ellos... o el token de acceso de nuestra empresa.

Aquí es donde las variables de entorno resultan útiles. Si no estás familiarizado con las variables de entorno, son variables que puedes establecer en cualquier sistema (Windows, Linux, lo que sea)... y luego puedes leerlas desde dentro de PHP. Muchas plataformas de alojamiento hacen que sea súper fácil establecerlas. ¿Cómo nos ayuda eso? Porque, en teoría, podríamos establecer nuestro token de acceso como una variable de entorno y luego simplemente leerlo en PHP. Eso nos permitiría evitar poner ese valor sensible dentro de nuestro código.

Lectura de variables de entorno

Pero, antes de hablar de establecer variables de entorno, ¿cómo leemos las variables de entorno en Symfony? Copia tu token de acceso para no perderlo, pon comillas simples alrededor de Token, y luego vamos a utilizar una sintaxis muy especial para leer una variable de entorno. En realidad va a parecer un parámetro. Empieza y termina con %, y dentro, di env() con el nombre de la variable de entorno. ¿Qué te parece GITHUB_TOKEN. Me acabo de inventar ese nombre:

... line 1
framework:
... lines 3 - 19
http_client:
scoped_clients:
githubContentClient:
base_uri: https://raw.githubusercontent.com
headers:
Authorization: 'Token %env(GITHUB_TOKEN)%'
... lines 26 - 32

Si volvemos atrás y refrescamos... ahora estamos leyendo esa variable de entorno GITHUB_TOKEN... pero aún no la hemos configurado, por lo que obtenemos este error "Variable de entorno no encontrada".

Configurar las variables de entorno y el .env

En el mundo real, configurar las variables de entorno es... en realidad algo complicado. Es diferente en Windows que en Linux. Y aunque muchas plataformas de alojamiento hacen que sea súper fácil configurar las variables de entorno, no es muy sencillo hacerlo localmente en tu ordenador.

Por eso existe este archivo .env. Muy sencillo, cuando Symfony arranca, lee el archivo .env y convierte todo esto en variables de entorno. Esto significa que podemos decir GITHUB_TOKEN= y pegar nuestro token... y ahora... ¡funciona!

22 lines .env
... lines 1 - 18
###
GITHUB_TOKEN=

Por cierto, si hubiera una variable de entorno real GITHUB_TOKEN en mi sistema, esa variable de entorno real ganaría a lo que tenemos en este archivo.

El archivo .env.local

Vale... esto es genial... ¡pero seguimos teniendo el mismo problema! Tenemos un valor sensible que está dentro de un archivo... que está comprometido en nuestro repositorio.

Bien, entonces, vamos a intentar otra cosa. Copia el token de GitHub, elimina el valor de este archivo y crea un nuevo archivo llamado .env.local. Establece la variable de entorno aquí.

Y ahora... ¡las cosas siguen funcionando!

Esto es lo que pasa. Cuando Symfony arranca, primero lee el archivo .env y convierte todo esto en variables de entorno. Luego lee .env.local y convierte todo lo que hay aquí en variables de entorno... que anulan cualquier valor establecido en .env.

El resultado es que tu archivo .env está destinado a contener valores seguros, por defecto, que están bien para ser consignados en tu repositorio. Entonces, localmente (y quizás también en producción, dependiendo de cómo se despliegue), creas un archivo .env.local y pones allí los valores sensibles. La clave es que .env.local es ignorado por Git. Puedes ver que ya está en nuestro archivo .gitignore. Así que, aunque este archivo contenga valores sensibles, no se confirmará en el repositorio.

Hay algunos otros archivos .env que puedes crear... y puedes verlos mencionados aquí. No son tan importantes, pero si quieres leer sobre ellos, puedes consultar la documentación.

Visualización de las variables de entorno con debug:dotenv

Otra cosa genial sobre las variables de entorno es que puedes visualizarlas ejecutando:

php bin/console debug:dotenv

¡Genial! Puedes ver el valor actual de GITHUB_TOKEN... y que este valor también está establecido en .env.local. En cambio, APP_ENV y APP_SECRET tienen n/aaquí, lo que significa que sus valores no están siendo anulados en .env.local. También nos dice qué archivos .env ha detectado.

Procesadores de variables de entorno

Hay algunos trucos que puedes utilizar con las variables de entorno. Por ejemplo, hay algo llamado "sistema de procesadores" en el que podrías utilizar trim para "recortar" el espacio en blanco en GITHUB_TOKEN. O podrías utilizar file donde la variable GITHUB_TOKENes en realidad una ruta a un archivo que contiene el valor verdadero. En cualquier caso, esto se llama "procesadores de variables de entorno" si quieres leer más sobre ellos.

A continuación, vamos a hablar rápidamente sobre el despliegue... pero aún más sobre cómo podemos almacenar de forma segura estos valores sensibles cuando se despliega a producción. Una opción es la bóveda de secretos de Symfony.

Leave a comment!

11
Login or Register to join the conversation
Akili Avatar

Hey SymfonyCast!

I'm getting a strange TransportException:

OpenSSL SSL_connect: Connection was reset in connection to raw.githubusercontent.com:443 for "https://raw.githubusercontent.com/SymfonyCasts/vinyl-mixes/main/mixes.json".

I'm not sure how to fix this.

Reply

Hey @Akili

That's very strange. Did you download the course code from this page? It's hard to know what's wrong but it could be a problem with your SSL certificate or your web server

Cheers!

Reply
Dmitriy Avatar

Can I programmatically change the value of an environment variable?

Reply

Hey Dmitriy,

I think you can because Symfony re-reads the .env file, but in my opinion, you should not change env vars unless you're deploying new stuff. I don't know what's your use case for it but makes me believe you're trying to solve it using the wrong approach

Cheers!

Reply
Dmitriy Avatar
Dmitriy Avatar Dmitriy | MolloKhan | posted hace 6 meses | edited

Hey MolloKhan,

Thanks for the answer.

I need to change ngrok url on production server every time i run it on localhost.

Found the following solution. I don't know how correct this is.

#[Route('/set_ngrok_url', name: 'set_ngrok_url')] 
public function set_ngrok_url(): Response
{ 
    $path = $this->getParameter('kernel.project_dir').'/.env.local';
    if (file_exists($path)) {
        file_put_contents($path, str_replace( 'NGROK_URL='.$_ENV['NGROK_URL'], 'NGROK_URL=333',    file_get_contents($path) ));
    } dd($_SERVER); 
}
Reply

Oh, I see, well, it should work, but in my opinion, you should not modify env vars at runtime, although this is just for dev purposes. Another approach would be to use the cache service

Cheers!

Reply
Massire-S Avatar
Massire-S Avatar Massire-S | posted hace 8 meses

hello, how did you find the token?

Reply
Brice P. Avatar
Brice P. Avatar Brice P. | posted hace 1 año

Hi I've got this issue on my install :


There is no extension able to load the configuration for "sentry" (in "/application/config/packages/sentry.yaml"). Looked for namespace "sentry", found ""framework", "sensio_framework_extra", "twig", "twig_extra", "web_profiler", "monolog", "debug", "webpack_encore", "knp_markdown"" in /application/config/packages/sentry.yaml (which is loaded in resource "/application/config/packages/sentry.yaml").
Reply
Brice P. Avatar

I've found, because I'm in dev environment, and into bundles.php, it was setted to 'prod'

Reply

Hey Brice,

Good catch, I'm happy to hear you were figured this out yourself!

Cheers!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=8.1",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "knplabs/knp-time-bundle": "^1.18", // v1.19.0
        "symfony/asset": "6.1.*", // v6.1.0-RC1
        "symfony/console": "6.1.*", // v6.1.0-RC1
        "symfony/dotenv": "6.1.*", // v6.1.0-RC1
        "symfony/flex": "^2", // v2.1.8
        "symfony/framework-bundle": "6.1.*", // v6.1.0-RC1
        "symfony/http-client": "6.1.*", // v6.1.0-RC1
        "symfony/monolog-bundle": "^3.0", // v3.8.0
        "symfony/runtime": "6.1.*", // v6.1.0-RC1
        "symfony/twig-bundle": "6.1.*", // v6.1.0-RC1
        "symfony/ux-turbo": "^2.0", // v2.1.1
        "symfony/webpack-encore-bundle": "^1.13", // v1.14.1
        "symfony/yaml": "6.1.*", // v6.1.0-RC1
        "twig/extra-bundle": "^2.12|^3.0", // v3.4.0
        "twig/twig": "^2.12|^3.0" // v3.4.0
    },
    "require-dev": {
        "symfony/debug-bundle": "6.1.*", // v6.1.0-RC1
        "symfony/maker-bundle": "^1.41", // v1.42.0
        "symfony/stopwatch": "6.1.*", // v6.1.0-RC1
        "symfony/web-profiler-bundle": "6.1.*" // v6.1.0-RC1
    }
}
userVoice