Переменные окружения.  Переменные окружения

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

Давайте подробнее взглянем на то:

  • как это работает?
  • действительно ли это хорошая идея?
  • как с ними работать в PHP?
  • и в заключение на некоторые рекомендации и распространенные ошибки, которых следует избегать - на те ловушки, на которые мы наткнулись в реальном мире!

Мы не будем рассматривать как настроить переменные окружения в вашем веб-сервере / Docker-е / crontab-ах... т. к. это зависит от системы, программного обеспечения, а мы хотим сосредоточиться на самих переменных окружения.

Если ваш хостинг использует Docker Swarm или AWS , все будет немного по-другому, например, т. к. они решили подсовывать файлы на файловую систему вашего контейнера, чтобы внедрить ваши секретные ключи, а не использовать переменные окружения. Это очень специфично для этих платформ и не является распространённым вариантом для всех.

Env vars 101

При запуске программы, она наследует все переменные окружения от своих родителей. Так что если вы установите переменную YOLO в значение covfefe в bash, а затем выполните команду, вы сможете прочитать YOLO в любом дочернем процессе.

$ YOLO=covfefe php -r "echo getenv("YOLO");" covfefe

Поскольку эта переменная определена только локально, мы не можем прочитать её из другого терминала (другого родителя). Идея в том, чтобы убедиться, что ваше приложение всегда наследует нужные переменные.

Вы можете посмотреть все переменные окружения в командной строке, выполнив следующую команду, но вы не увидите переменной YOLO , т. к. она была передана только в команду php "на лету", а не установлена в текущем процессе:

Вы можете установить переменную окружения с помощью export <имя>=<значение> :

$ export YOLO=covfefe

Имена переменных чувствительны к регистру и соглашение заключается в использовании имён только на английском, в верхнем регистре, с _ в качестве разделителя (т. н. "змеиный" стиль в верхнем регистре). Вы уже наверняка знаете некоторые переменные - такие как PATH , DISPLAY , HTTP_PROXY …

Лучшие практики на сегодня

josegonzalez/dotenv , ориентирована на безопасность:

Эта библиотека не заполнит суперглобальные переменные по умолчанию:

$Loader = new josegonzalez\Dotenv\Loader("path/to/.env"); // Парсим файл.env: $Loader->parse(); // Отправляем результат парсинга.env в переменную $_ENV: $Loader->toEnv();

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

symfony/dotenv , новый малыш на этом поприще:

Доступен начиная с Symfony 3.3. Этот компонент заботится о.env -файле, как остальные, и тоже заполняет суперглобальные массивы:

$dotenv = new Symfony\Component\Dotenv\Dotenv(); $dotenv->load(__DIR__."/.env"); $dbUser = getenv("DB_USER"); $dbUser = $_ENV["DB_USER"]; $dbUser = $_SERVER["DB_USER"];

Вы не должны использовать её для получения ваших значений, поэтому я предлагаю вам вместо этого обращаться к $_SERVER - к тому же есть небольшая разница в производительности между обращением к массиву и вызовом функции в пользу массивов.

Переменные окружения - всегда строки

Одной из главных проблем является то, что сейчас в PHP есть указание типов, а наши настройки не всегда правильно набраны.

Class Db { public function connect(string hostname, int port) { } } // Это не будет работать: $db->connect($_SERVER["DATABASE_HOSTNAME"], $_SERVER["DATABASE_PORT"]);

В Symfony теперь можно преобразовывать variables , а даже больше - чтение файла, декодирование json...…

Переменные окружения везде или нет

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

Но если правильно использовать, в приложении на Symfony, например, переменные окружения могут быть изменены "на лету" - без очистки какого-либо кеша, без обращения к файловой системе, без развертывания кода: просто перезапустив процесс, например.

Тенденция иметь только одну переменную, как APP_CONFIG_PATH , и читать её через "%env(json:file:APP_CONFIG_PATH)%" для меня выглядит как заново изобретать старый добрый parameters.yml , если файл не управляется автоматически с помощью надежного инструмента (как AWS Secret Store). И также есть envkey.com , который позволяет управлять вашими переменными окружения из одного места, не возясь с файлами самостоятельно, мне нравится такой подход, т. к. это гораздо проще!

Внимание! Статья написана под Windows 7, но принципиальных отличий в добавлении PHP в переменные среды в другие версии (Window XP, Windows Vista, Windows 8, ...) нет.

Информация! Все пути в настройках будут указаны исходя из того, что Denwer установлен в папку D:/web . При использовании данных из статьи не забудьте поменять этот путь на свой.

Для удобного использования PHP в консоле Windows необходимо настроить переменные среды. Иначе при работе с PHP через консоль вместо команды php Вам будет необходимо писать полный путь к файлу php.exe .

Предположим, что Denwer у нас установлен в папку D:/web .

Кликаем правой кнопкой мыши по иконке "Компьютер" Свойства:

Дополнительные параметры системы:

Вкладка "Дополнительно", кнопка "Параметры среды...":

Группа "Системные параметры", выделите переменную Path и нажмите кнопку изменить:

Добавьте строку D:\web\usr\local\php5; и нажмите кнопку "Ок":

Перезапустите Denwer. Теперь Вы можете открыть консоль (Win + R и введите cmd) и проверить работу PHP , введите команду:

Для исправления этих ошибок откройте файл D:/web/usr/local/php5/php.ini . Найдите переменные extension_dir , zend_extension , session.save_path и установите для них следующие значения.

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

HTTP_ACCEPT - В этой переменной перечислены все MIME-типы данных, которые могут быть восприняты браузером. Строка */* означает, что браузер понимает любой тип.

HTTP_ACCEPT= */*

HTTP_REFERER - Эта переменная представляет сведения о странице, с которой пользователь попал на данную. Эту переменную можно использовать, например, для отслеживания перемещения пользователя по вашему сайту, а затем просматривать наиболее популярные маршруты.

HTTP_REFERER= http://www.spravkaweb.ru/

HTTP_COOKIE - В этой переменной храняться все Cookies в URL-кодировке.

HTTP_COOKIE=

HTTP_USER_AGENT - Идентифицирует браузер пользователя. Для установления типа браузера нужно проверить эту строку на наличие слов: если браузер - Internet Explorer, то будет присутствовать подстрока MSIE, а если в наличии лишь слово Mozilla, то это Netscape.

HTTP_USER_AGENT= Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 4.0)

У вас Internet Explorer

HTTP_HOST - Содержит доменное имя Web-сервера, на котором запустился сценарий. Эту переменную достаточно удобно использовать, например, для генерации полного пути, который требуется в заголовке Location, чтобы не привязываться к конкретному серверу.

HTTP_HOST= www.spravkaweb.ru

HTTP_FROM - Адрес электронной почты пользователя, направившего запрос.

HTTP_FROM=

SERVER_NAME - Доменное имя или IP-адрес сервера.

SERVER_NAME= www.spravkaweb.ru

SERVER_SOFTWARE - Имя и версия программы-сервера, отвечающей на запрос клиента.

SERVER_SOFTWARE= Apache/1.3.33 (Unix) mod_jk/1.2.8 mod_auth_passthrough/1.8 mod_log_bytes/1.2mod_bwlimited/1.4 FrontPage/5.0.2.2635 mod_ssl/2.8.22 OpenSSL/0.9.7a PHP-CGI/0.1b

SERVER_PORT - Эта переменная содержит порт сервера, к которому обратился браузер пользователя. Обычно это 80. Переменная так-же может применяться для формирования параметра заголовка Location.

SERVER_PORT= 80

SERVER_PROTOCOL - Переменная содержит имя и версию информационного протокола, который был использован для запроса.

SERVER_PROTOCOL= HTTP/1.0

REMOTE_ADDR - Эта переменная содержит IP-адрес (или доменное имя) узла пользователя, на котором был запущен браузер.

REMOTE_ADDR= 212.94.114.177

REMOTE_PORT - Порт, который закрепляется за браузером пользователя для получения ответа сервера.

REMOTE_PORT= 4277

REMOTE_USER - Идентификационное имя пользователя, посылающего запрос.

REMOTE_USER=

SCRIPT_NAME - Содержит имя файла, содержащего данный сценарий. Эту переменную удобно использовать при формировании заголовка Location при переадресации на себя (self-redirect), а также для подставления значения атрибута action тега

на странице, которую вызывает сценарий при запуске без параметров (для того чтобы не привязываться к конкретному имени сценария).

SCRIPT_NAME= /pril.php

DOCUMENT_ROOT - Корневой каталог дерева Web-документов.

DOCUMENT_ROOT= /home/spravka/public_html

REQUEST_METHOD - Метод, который применяет пользователь при передаче данных. Надо заметить, что грамотно составленный сценарий должен сам определять на основе этой переменной, какой метод задействует пользователь, и принимать данные из соответствующего источника, а не расчитывать, что передача будет осуществляться, например, только методом POST.

REQUEST_METHOD= GET

QUERY_STRING - Содержит параметры, которые в URL указаны после вопросительного знака. Напомним, что они доступны как при методе GET, так и при методе POST (если в последнем случае они были определены в атрибуте action тега ).

QUERY_STRING= ss=getenv

PATH_INFO - Содержит дополнительную информацию о пути.

PATH_INFO=

PATH_TRANSLATED - Та же информация, что и в переменной PATH_INFO с префиксом, задающим путь к корневому каталогу дерева Web-документов.

PATH_TRANSLATED=

CONTENT_TYPE - Медиа-тип данных запроса.

CONTENT_TYPE=

CONTENT_LENGTH - Возвращает количество байт данных, присланных пользователем. Эту переменную необходимо анализировать, если вы занимаетесь приемом и обработкой POST-формы.

GATEWAY_INTERFACE - Версия CGI, которую использует сервер.

GATEWAY_INTERFACE= CGI/1.1


Переменные окружения

Переменные окружения:




echo "Вы пришли из: ".getenv("HTTP_REFERER")."
";
$br=getenv("HTTP_USER_AGENT");
if(strpos($br,"MSIE")!==false) echo "У вас Internet Explorer
";
else echo "У вас Netscape или др.
";
echo "Ваш IP: ".getenv("REMOTE_ADDR")."
";
echo "Вот параметры в строке браузера: ".getenv("QUERY_STRING");
?>

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

HTTP_ACCEPT

В этой переменной перечислены все MIME-типы данных , которые могут быть восприняты браузером. Строка */* означает, что браузер понимает любой тип.

HTTP_ACCEPT= image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/msword, */*

HTTP_REFERER

Эта переменная представляет сведения о странице, с которой пользователь попал на данную. Эту переменную можно использовать, например, для отслеживания перемещения пользователя по вашему сайту, а затем просматривать наиболее популярные маршруты.

HTTP_REFERER= http://www.сайт/php/pril/

HTTP_COOKIE

В этой переменной хранятся все Cookies в URL-кодировке.

HTTP_COOKIE= hotlog=1; ZDEDebuggerPresent=php,phtml,php3; b=b; PHPSESSID=

HTTP_USER_AGENT

Идентифицирует браузер пользователя. Для установления типа браузера нужно проверить эту строку на наличие слов: если браузер - Internet Explorer, то будет присутствовать подстрока MSIE, а если в наличии лишь слово Mozilla, то это Netscape.

Например:

HTTP_USER_AGENT= Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; Maxthon)

HTTP_HOST

Содержит доменное имя Web-сервера, на котором запустился сценарий. Эту переменную достаточно удобно использовать, например, для генерации полного пути, который требуется в заголовке Location, чтобы не привязываться к конкретному серверу.

HTTP_HOST= www.сайт

HTTP_FROM

Адрес электронной почты пользователя, направившего запрос.

SERVER_NAME

Доменное имя или IP-адрес сервера.

SERVER_NAME= www.сайт

SERVER_SOFTWARE

Имя и версия программы-сервера, отвечающей на запрос клиента.

SERVER_PORT

Эта переменная содержит порт сервера, к которому обратился браузер пользователя. Обычно это 80. Переменная так-же может применяться для формирования параметра заголовка Location.

SERVER_PORT= 80

SERVER_PROTOCOL

Переменная содержит имя и версию информационного протокола, который был использован для запроса.

SERVER_PROTOCOL= HTTP/1.1

REMOTE_ADDR

Эта переменная содержит IP-адрес (или доменное имя) узла пользователя, на котором был запущен браузер.

REMOTE_PORT

Порт, который закрепляется за браузером пользователя для получения ответа сервера.

REMOTE_USER

Идентификационное имя пользователя, посылающего запрос.

SCRIPT_NAME

Содержит имя файла, содержащего данный сценарий. Эту переменную удобно использовать при формировании заголовка Location при переадресации на себя (self-redirect), а также для подставления значения атрибута action тега на странице, которую вызывает сценарий при запуске без параметров (для того чтобы не привязываться к конкретному имени сценария).

DOCUMENT_ROOT

Корневой каталог дерева Web-документов.

REQUEST_METHOD

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

QUERY_STRING

Содержит параметры, которые в URL указаны после вопросительного знака. Напомним, что они доступны как при методе GET, так и при методе POST (если в последнем случае они были определены в атрибуте action тега ).

PATH_INFO

Содержит дополнительную информацию о пути.

PATH_TRANSLATED

Та же информация, что и в переменной PATH_INFO с префиксом, задающим путь к корневому каталогу дерева Web-документов.

CONTENT_TYPE

Медиа-тип данных запроса.

CONTENT_LENGTH

Возвращает количество байт данных, присланных пользователем. Эту переменную необходимо анализировать, если вы занимаетесь приемом и обработкой POST-формы.

GATEWAY_INTERFACE

Версия CGI, которую использует сервер.

Пример использования переменных окружения

Переменные окружения

Переменные окружения:


"; $br=getenv("HTTP_USER_AGENT"); if(strpos($br,"MSIE")!==false) echo "У вас Internet Explorer
"; else echo "У вас Netscape или др.
"; echo "Ваш IP: ".getenv("REMOTE_ADDR")."
"; echo "Вот параметры в строке браузера: ".getenv("QUERY_STRING"); ?>