Oc-windows.ru

IT Новости из мира ПК
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Php environment variable

Заставляем сервис php-fpm 5.6, запущенный через systemd, читать глобальные переменные окружения

Это короткий how-to для реализации конфигурации php-сервиса, зависимого от окружения, в котором он запущен. Я буду рад, если кто-то подскажет более изящное решение или поправит в мелочах.

Основная идея

Запускать сервис, микросервисы и зависимые приложения в рамках одной экосистемы, конфигурируемой с помощью переменных окружения.

Проблема
Предыстория

Этот раздел можно пропустить, если вы уже работали с .env

В данный момент я работаю над проектом, написанном на ZF2. Для конфигурации проекта использовались конфиг-файлы для разных окружений. Это порождает большое количество дубликатов конфигурации в репозитории проекта примерно такого вида:

  • session.global.php
  • session.local.php.dist
  • session.unittest.php.dist
  • db.global.php
  • db.local.php.dist
  • db.unittest.php.dist
  • .

Эти дубликаты приходится постоянно синхронизировать друг с другом. Кроме того, они хранят определённую php-логику внутри себя, что порождает дублирование кода.

Я добавил к проекту библиотеку, которая умеет считывать окружение из .env файла и загружать его в $_ENV (упрощённо).

composer require vlucas/phpdotenv

Открыть public/index.php
После require ‘init_autoloader.php’ добавить:

Кроме того (это совершенно необязательно), добавил helper-функцию env() из laravel, которая является обёрткой над php getenv().

Создать файл, например library/Common/Config/env.php, с содержимым:

В composer.json добавить в секцию «autoload»:

Затем выполнить composer dumpautoload.

Этот шаг позволил выбросить из репозитория все лишние дубликаты конфиг-файлов (local.php, unittest.php, *.php.dist). Вместо этого в корне проекта появился .env.global со списком всех доступных переменных, которые задействованы в конфигах.

Не окружение знает о переменных сервиса, а сервис учитывает окружение, в котором он запущен.
1. Т.к. на рабочей машине в переменных окружения может ничего и нет, да и обмениваться проектом неудобно между разными машинами, библиотека phpdotenv перед запуском приложения считывает .env файл и загоняет его переменные в $_ENV[$name] = $value.
2. Конфигурационные файлы вызывают метод env(), который является обёрткой над php-функцией getenv(), и читает переменные окружения, подставляя значение по-умолчанию по необходимости.

3. Файл .env не обязательно заполнять. Можно использовать глобальные переменные окружения или значения по-умолчанию в конфигурации. При отсутствии .env файла бросается exception (особенность библиотеки, не самая правильная), на production сервере её можно вообще не подключать. Для избежания exception, файл необходимо просто создать в корне проекта (touch .env).
4. Файл .env не обязательно должен хранить все доступные переменные проекта. Если в конфигах устанавливаются значения по-умолчанию, достаточно записывать в .env только переменные, отличающиеся в данном окружении.
5. Файл .env не нужно коммитить в репозиторий. Его следует добавить в ignore для системы контроля версий.
6. Чтобы сделать переменную окружения обязательной, в index.php необходимо добавить такую конструкцию:

7. В репозитории проекта можно коммитить файлы вида .env.* (.env.phpunit, .env.develop). Это не что иное, как закладки с набором переменных для разного окружения. Оркестратор или CI-система просто копирует шаблон (или переменные из него) при разворачивании проекта там, где проект разворачивается в нескольких копиях в рамках одной системы или нет возможности оперировать глобальными переменными окружения. Закладки удобно сравнивать друг с другом. Эти закладки никак не участвуют в логике сервиса.

Важно: .env.production не должен храниться в репозитории проекта.
Удобно создать .env.default – файл, который содержит все переменные окружения, поддерживаемые в проекте на текущий момент (максимально-возможный template для .env).

Так что, теперь все конфиги нужно дублировать в .env? Когда добавлять новую переменную окружения?

Выносить конфигурацию в окружение стоит в том случае, если эта опция может отличаться на разных хостах.
Нет ничего плохого в том, чтобы записать нечто в переменные среды.

А как быть с паролями и чувствительными данными?

Храните production-данные в отдельном репозитории, в хранилище паролей или, например, в защищенном хранилище оркестратора.

Итак, проект теперь учитывает окружение, но.

Пока разработка велась на рабочих машинках, проект читал .env файл и всё работало. Но когда я развернул тестовую среду, оказалось, что если задать взаправдашние системные переменные окружения, php-fpm их игнорирует. Различные рецепты из гугла и StackOverflow сводились к той или иной автоматизации использования двух известных способов:

1. Передача переменных через nginx параметром fastcgi_param SOMEENV test;
2. Установкой переменных в формате env[SOME_VAR] в конфигурации пула рабочих процессов php-fpm.

И первый, и второй вариант, удобны для каких-то особых ситуаций. Но если мыслить в парадигме «конфигурировать среду, а не приложение», то подобные способы оказываются куда труднее, чем например просто положить .env файл в папку с проектом. Но ведь оркестратор, CI-система или просто системный администратор не должен знать детали реализации проекта, это не изящно.

Предлагаемый способ решения

Скомбинировав различные рецепты из сети, я нащупал следующее рабочее решение.
Тестировалось под Centos 7, PHP 5.6.14.

Этот же подход с симлинком, в теории, применим и к другим сервисам.

Плюсы предложенного решения:
— Переменные, хранящиеся в /etc/environment, доступны разным приложениям. Можно вызвать echo $MYSQL_HOST в shell или getenv(‘MYSQL_HOST’) в php.
— Переменные окружения, которые явно не заданы в /etc/environment, не попадут в php-fpm. Это позволяет с помощью оркестратора контролировать окружение извне изолированной системы, в которой запущен сервис.

Минусы:
— К сожалению, у php-fpm я не нашел работающей команды для reload по аналогии с nginx, так что в случае изменения /etc/environment, обязательно нужно делать systemctl daemon-reload && service php-fpm restart.

Важно: если ваше приложение работает не в изолированной среде (сервер, виртуалка, контейнер), определение переменных окружения может непредсказуемо повлиять на соседние сервисы в системе из-за совпадений имён в глобальном пространстве.

Ссылки:
— Для тех, кто не читал статью
— Методология двенадцати факторов разработки SAAS: храните конфигурацию в окружении (англ.)
— Загрузка переменных окружения с помощью .env-файлов для development environment в php-проектах.

Управление переменными среды в PHP

Имея богатый опыт работы с языками программирования, при использовании PHP я зачастую не нахожу уже привычных и подходящих средств, которые применял и применяю в других языках. Одним из таких случаев, является установка переменных окружения, в частности во время разработки. В NodeJS существует библиотека dotenv, которая отлично справляется со своими обязанностями. Но и PHP, конечно, не остался в стороне – в нем тоже есть похожая библиотека, называемая phpdotenv.

Читать еще:  Php pdo execute

Управление переменными среды

Основная идея, которая стоит за механизмом управления переменными среды, заключается в том, что чтение переменных, требующихся для настройки окружения в PHP, происходит из локального текстового файла, а не из реальных переменных среды. Это облегчает настройку, так как для каждого проекта создается отдельный файл конфигурации, и нет необходимости заново экспортировать переменные среды. Дополнительное преимущество заключается в том, что при написании кода, который будут использовать другие разработчики, файлы конфигурации (.env ) обеспечивают простой и ясный список значений, для конфигурирования проекта.

Файл конфигурации .env

Обычно используются два файла:

  1. .env – это файл, откуда будут браться необходимые настройки. Обязательно добавьте имя файла в .gitignore, если пользуетесь системой контроля версий, чтобы при сохранении проекта в репозитории не сохранились бы какие-либо секретные настройки, вроде паролей, ключей авторизации и так далее.
  2. .env-example – этот файл содержит просто ключи, а не значения. Благодаря этому можно просто скопировав файл, добавить необходимые значения в требуемые ключи.

Примерное содержимое .env файла.

Значения в файле .env есть, теперь пора настроить PHP для работы с ним.

Для начала добавляем пакет phpdotenv в наш проект, используя Composer.

composer require vlucas/phpdotenv

Далее, например, в файле index.php можете добавить (сразу за «vendor/autoload.php»):

$dotenv = new DotenvDotenv(__DIR__);
$dotenv->load();

После этого все переменные будут доступны, там, где их можно ожидать в PHP – в суперглобальном массиве $_ENV.

Использовать переменные среды в разработке так же просто, как использовать файлы конфигурации, но это больше похоже на то, как мы обычно настраиваем приложения в производственной среде. Переменные среды — это очень простой способ передачи контекста приложению — отсюда и название! Они буквально сообщают приложению о среде, в которой оно работает.

Надеюсь, вы найдете использование библиотеки phpdotenv полезным для собственных приложений.

Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Порекомендуйте эту статью друзьям:

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

Она выглядит вот так:

  • BB-код ссылки для форумов (например, можете поставить её в подписи):
  • Комментарии ( 0 ):

    Для добавления комментариев надо войти в систему.
    Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.

    Copyright © 2010-2020 Русаков Михаил Юрьевич. Все права защищены.

    What you need to know about environment variables with PHP

    Environment variables for configuration are today’s best practice for application setup – database credentials, API Keys, secrets and everything varying between deploys are now exposed to the code via the environment, instead of configuration files or worse, directly hard-coded.

    • how does it work?
    • is it really a good idea?
    • how to deal with them in PHP?
    • and finally some recommendations and common errors to avoid – with some real world traps we fell into!

    We are not going to cover how to setup environment variables in your webserver / Docker / crontabs… as it depends on the system, the software and we want to focus on env vars.

    If your hosting is using Docker Swarm or AWS, things will be a little bit different for example, as they decided to push files on your container filesystem to expose your secrets, not env vars: that’s very specific to those platforms and not a standard at all.

    Env vars 101

    When you run a program, it inherits all environment variables from its parent. So if you set a variable named YOLO with the value covfefe in your bash and then run a command, you will be able to read YOLO in any child process.

    As this variable is only locally defined, we can’t read it from another terminal (another parent). So the idea is to make sure your application always inherits the needed variables.

    You can see all environment variables in your shell by running the following command, but as you will not see the YOLO variable yet because it was only passed to the php command on the fly, not set in the current process:

    You can set an environment variable with the syntax export = :

    Variable names are case sensitive and the convention is to only use English, uppercase names with _ as separator (upper snake case). You already know some like PATH , DISPLAY , HTTP_PROXY , …

    Today’s best practice

    You may already know the twelve-factor methodology to build robust and scalable applications (if not, I suggest you take a break and check it out). The Configuration chapter explains why storing configuration in the environment is the way to go:

    • Config varies substantially across deploys (production, staging, testing…), code does not;
    • Env vars are easy to change between deploys without changing any code;
    • They are a language – and OS – agnostic standard. The same configuration can be shared between your PHP and Python processes.
    Читать еще:  Php sql limit

    The manifesto also describes quite well what should be in the code and what should be in the environment – do not put your whole application configuration in it, only what differ from one deploy to another .

    I read on the Internet that env vars are dangerous

    Some articles will tell you that env vars are harmful for your secrets; the main reason is that any process inherits from his parent variables, all of them. So if you have a very secret setting in the environment, child processes will have access to it:

    Child processes can consider environment variable to be something public, writable into logs, to include in bug reports, to dump to the user in case of error… They can leak your secrets.

    The alternative is plain old text files, with strong Unix permissions. But what should really be done is clearing the environment when running a child process you do not trust, like nginx does. By default, nginx removes all environment variables inherited from its parent process except the TZ variable. Problem solved!

    This can be done with env -i which tells to start the following commands with an empty environment.

    Always run processes you do not trust in a restricted environment.

    Even if you trust your code, you should still be very careful and expose your variables to the least possible processes – you never know (NPM Drama inside).

    Getting your PHP application ready

    When dealing with env vars in a PHP project, you want to make sure your code is going to always get the variable from a reliable source, be it $_ENV , $_SERVER , getenv … But those three methods are not returning the same results!

    This is because of the variables_order PHP setting on my machine which is GPCS , as there is no E I can’t rely on the $_ENV superglobal. This can lead to code working on one PHP installation and not the other.

    Another point is that developers don’t want to manage env vars locally. We do not want to edit VirtualHost all the time, reloading php-fpm, rebooting some services, clearing caches… Developers wants a simple and painless way of setting environment variables… like a .env file!

    An .env file is just a compilation of env vars with their values:

    Dot Env libraries to the rescue

    vlucas/phpdotenv, the most popular library at the moment

    This library will read a .env file and populate all the superglobals:

    There are some nice additions like the ability to mark some variables as required (and this is the one used by Laravel).

    josegonzalez/dotenv, security oriented

    This library doesn’t populate the superglobals by default:

    It supports required keys, filtering, and can throw exceptions when a variable is overwritten.

    symfony/dotenv, the new kid on the block

    Available since Symfony 3.3, this component takes care of the .env file like the others, and populates the superglobals too:

    There is more on packagist and at that point I’m too afraid to ask why everyone is writing the same parser all over again.

    But they are all using the same logic:

    • find a .env file;
    • parse it, check for nested values, extract all the variables;
    • populate all the superglobals only for variables not already set.

    I recommend to commit a .env file with values made for the developers: everyone should be able to checkout your project and run it the way they like (command line server, Apache, nginx…) without dealing with configuration.

    This recommendation work well when everyone has the same infrastructure locally: same database password, same server port… As we use Docker Compose on all our projects we never have any difference from one developer to another, if you don’t have this luxury, just allow developers to overwrite the defaults by importing two files:

    That way you just have to create and populate a .env.dev file with what’s different for you (and add it to .gitignore ).

    Then on production, you should not load those default values, so the idea is to protect the loader with an env var only set in production:

    If you don’t do that and your hosting provider forgot a variable, you are going to run development settings in production and have a bad time.

    The pitfalls you have to look for ⚠

    Name conflicts

    Naming is hard, and env vars don’t escape this rule.

    So when naming your env vars, you have to be specific and avoid as much as possible name collision. As there is no official list of reserved names, it’s up to you. Prefixing custom variables can’t harm.

    The Unix world do it already, with LC_ , GTK_ , NODE_ …

    Missing variables at runtime

    You have two choices when a variable is missing: either throw an Exception, or use a default value. That’s up to you but the second one is silent… Which can cause harm in a lot of contexts.

    As soon as you want to use env vars, you have to set them everywhere:

    • in the webserver;
    • in the long running scripts and services;
    • in the crontabs…
    • and in the deployment scripts!

    The last one is easy to miss, but as some deployment can warm application cache (like Symfony’s)… Yep, a missing variable can lead to a corrupted application delivery. Be strict about them and add a requirement check on your application startup.

    Читать еще:  Php artisan key generate

    The HTTP_ prefix

    There is just one prefix you should never use: HTTP_ . Because this is the one used by PHP itself (and other CGI-like contexts) to store HTTP request headers.

    Do you remember the httpoxy security vulnerability? It was caused by HTTP Client looking for this variable in the environment, in a way that could be set via a simple HTTP header.

    Some DotEnv libraries also prevent override of those variables, like the Symfony one.

    Thread safety of getenv()

    I have a bad news: in some configurations, using the getenv function will result in unexpected results. This function is not thread safe!

    You should not use it to retrieve your values, so I suggest you call $_SERVER instead – there is also a small performance difference between an array access and a function call for what it’s worth.

    Env vars are always strings

    One of the main issue now that we have type casting in PHP is that our settings coming from env vars are not always properly typed.

    Symfony now allow to cast variables, and more like reading a file, decoding JSON…

    Env vars everywhere, or not

    There is a lot of debates at the moment between env vars, files, or a mix of it: env vars referencing a configuration file. The fact is that despite being considered a best practice, env vars are not introducing a lot of advantages…

    But if properly used, in a Symfony application for example, env vars can be changed on the fly, without clearing any cache, without doing any filesystem access, without deploying code: just by restarting a process, for example.

    The trend to have just one variable, like APP_CONFIG_PATH , and reading it via ‘%env(json:file:APP_CONFIG_PATH)%’ looks like re-inventing the good old parameters.yml to me, unless the file is managed automatically by a trusted tool (like AWS Secret Store). There is also envkey.com which allow to control your env vars from one location, without dealing with files yourself, I like this approach as it’s closer to the simplicity of Heroku-like hosting!

    What are you using to expose your credentials to your application? Do you have any pro-tips ©️ to share about env vars? Please comment!

    Nos formations sur le sujet

    Symfony

    Formez-vous à Symfony, l’un des frameworks web PHP les plus connus au monde

    Using Environment Variables in PHP

    Browse by products and services

    Grid Shared Hosting

    • Service Type: Grid
      • Difficulty: Medium
      • Time Needed: 10
      • Tools Required: None

    Environment variable definition

    PHP environment variables allow your scripts to glean certain types of data dynamically from the server. This supports script flexibility in a potentially changing server environment. For example, the SITE_HTMLROOT variable provided by (mt) Media Temple will automatically provide the correct path to your document root on any Grid server, without necessitating any changes in your script. (mt) Media Temple provides several dozen variables like this for your convenience.

    This article is provided as a courtesy. Installing, configuring, and troubleshooting third-party applications is outside the scope of support provided by (mt) Media Temple. Please take a moment to review the Statement of Support.

    Use and examples

    You can access these variables using the $_SERVER and $_ENV arrays.

    For example, if you want to use the SITE_HTMLROOT variable mentioned above, you can create a variable in your PHP script similar to the following:

    This will create a variable with a value similar to the following:

    If you want to test the output of the variable, add an echo statement to your PHP script. For example:

    Now visit your script in your browser to see the output.

    $_SERVER and $_ENV are PHP superglobal arrays. They do not have to be declared as global variables. Do NOT put the following line in your file:

    Practical use

    On the Grid, it is particularly helpful to use a few select environment variables, for three reasons. First, if you ever decide to re-use a script on a different domain on the Grid, you won’t have to change all your variables. Second, the variables are often more convenient than the long path and server names used for the Grid architecture. Third, the Grid load-balancing occasionally requires sites and databases to be shifted to different physical machines, which can change your environment. This is not a common occurrence, but it is an essential part of Grid functionality.

    • $_SERVER[«SITE_HTMLROOT»]
      The full path to your site’s document root, returns output like /home/00000/domains/example.com/html.
    • $_ENV[«DATABASE_SERVER»] — The internal database server name, returns output like internal-db.s00000.gridserver.com.

    Complete list of provided variables

    Create a phpinfo.php page to view all of your (mt) Media Temple-prov >PHP Variables section of the page for the relevant information.

    Setting your own variables

    In PHP

    On the Grid, you can set your own environment variables that will last within the session that created them. For example, if you want to use a custom environment variable in a script, you can add the following lines to create and then use a variable:

    Note: These environment variables will not last outside the session in which they were created.

    In .htaccess

    You can also have Apache set environment variables for use in your scripts, via a .htaccess file, using SetEnv or in Rewrite rules. These variables must start with ‘HTTP_’ for security purposes.

    Ссылка на основную публикацию
    Adblock
    detector