【第3回】「dotenv(.env)」で環境別の設定や認証情報を使う

【第3回】Composerを使ってお手軽アプリケーション開発

本連載ではComposerで公開されているパッケージの中から、フレームワークを問わず汎用的に使えるライブラリをサンプルコードと共に紹介します。

今回は「dotenv(.env)」という、アプリケーション内で使用する環境変数を読み込むパッケージを紹介します。

dotenv(.env)の概要

dotenvはファイルから環境変数を読み込み、$_SERVERやgetenv()を使用して設定した環境変数を読み込むことができます。
dotenvに記述するフォーマットはPHPだけでなくRuby、Node.jsやPythonなど他の言語でも環境変数として利用するためのパッケージが用意されています。

もちろん、LaravelSymfonyのようなPHPのメジャーなフレームワークでもdotenvが使われています。

dotenvの導入方法

dotenvのパッケージは幾つか存在しますが、今回は一番スター数の多いvlucas/phpdotenvのパッケージについて説明していきます。

インストールは他のライブラリ同様

composer require vlucas/phpdotenv

を実行するか、composer.jsonに下記を記載して、composer updateを実行します。

{
    "require": {
        "vlucas/phpdotenv": "^2.5"
         }
}
2018/10/22時点の最新バージョンは2.5.1です。

dotenvの役割

なぜdotenvのようなパッケージが幅広い言語で用意されているかというと、開発や本番などの環境によって変わる値をアプリケーションで使う場面が多いからです。
特にデータベースの接続情報やAPIの鍵といったGitなどのバージョン管理に含めることができない設定値をアプリケーションで利用するために.envファイルを作成します。

バージョン管理方法

上記で説明した通り機密情報を含むことがあるため、.envファイル自体は.gitignoreに追加するなどしてバージョン管理の対象外とすることが多いです。
しかし、バージョン管理外にすると、何を.envファイルに記述すればよいか分からなくなってしまうため、
.envの設定値をダミーデータにして.env.exampleのようなファイルをバージョン管理下に指定するようにします。

dotenvの使い方

下記のサンプルはデータベースの接続情報を記載した.envファイルです。

DB_HOST=localhost
DB_USER=user
DB_PASS=password
DB_NAME=database

これをPHPで読み込み、PDOに接続するまでのサンプルがこちらです。
コード内でgetenv()$_SERVER$_ENVと異なる方法で呼び出しているように、通常の環境変数を呼び出すのと同じように複数の方法で環境変数を呼び出すことができます。

<?php
require_once __DIR__ . '/vendor/autoload.php';

$dotenv = new Dotenv\Dotenv(__DIR__); // .envファイルがあるディレクトリを指定
$dotenv->load();                      // .envファイルから環境変数を読み込み

// 通常の環境変数を同じように下記のどの方法でも環境変数を呼び出せます
$host = getenv('DB_HOST');
$user = $_SERVER['DB_USER'];
$password = $_ENV['DB_PASS'];

$dsn = "mysql:host={$host};charset=utf8;";
$options = [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
];

$this->pdo = new PDO($dsn, $user, $password, $options);

コメントやスペースの扱い方

.envファイルの中にコメントを書きたいときや、値としてスペースを入れたいときは下記のようなルールに従って書く必要があります。

  • #(シャープ)以降はコメントになります
  • 環境変数の中にシャープを入れたいときは「"」または「'」で囲う必要があります
  • 先頭や末尾に半角スペースを入れたいときも「"」または「'」で囲う必要があります
# #(シャープ)以降はコメントになります
COMMENT_SAMPLE=hogehoge # 行途中のシャープ以降もコメントになる

# 環境変数の中にシャープを入れたいときは「"」または「'」で囲う
SALT_STR="#(5$sxdfSaD"

# 半角スペースはtrimされて消えてしまうので、先頭や末尾に半角スペースを入れたいときも「"」または「'」で囲う
SEPARATER = " | "

注意すること

.envファイルの内容はすべてテキストとして扱われるので、数値やbool値として環境変数を使用することはできません。

STR=HELLO  # 文字列の"HELLO"
NUMBER=10  # 文字列の"10"
BOOL=false # 文字列の"false" ※bool型にキャストするとtrueになります

特に、bool値を扱おうとするときに.envファイルにfalseと書いても、PHPの型変換ではtrueとして扱われるので気をつける必要があります。

<?php

require_once __DIR__ . '/vendor/autoload.php';

$dotenv = new Dotenv\Dotenv(__DIR__);
$dotenv->load();

var_dump(getenv('STR'));             // string(5) "HELLO"
var_dump(getenv('STR') === 'HELLO'); // bool(true)
var_dump(getenv('NUMBER'));          // string(2) "10"
var_dump(getenv('NUMBER') === 10);   // bool(false)
var_dump(getenv('BOOL'));            // string(5) "false"
var_dump((bool) getenv('BOOL'));     // bool(true)

dotenvの中で別の環境変数を使いたい

前の行までに宣言している環境変数は.envファイルの中でも使うことができます

APP_PATH=/app                       # /app
STORAGE_PATH=${APP_PATH}/storage    # /app/storage 
UPLOAD_PATH=${STORAGE_PATH}/uploads # /app/storage/uploads

WordPressでdotenvを使う

WordPressをバージョン管理したり、複数の環境で利用する際にwp-config.phpの扱いに迷うことがありますが、
WordPressもPHPで動いているので、もちろんdotenvを導入することが可能です

例として下記のようなディレクトリ構成の場合での使い方を説明します。
composer.jsonでvlucas/phpdotenvを読み込んでいる前提で進めますので、ご注意ください。

/
├htdocs [ドキュメントルート]
│ ├ index.php
│ ├ wp-config.php
│ └ その他WordPressファイル
├ composer.json
├ vender
│ └ autoload.php
├ .env
└ .env.example

使い方は単純にwp-config.phpの先頭でautoload.phpを読み込み、Dotenvを使用するだけです。
下の例では一度load後はインスタンスを使用しないので、インスタンスを変数に格納せず、直接loadメソッドを実行しています。

<?php
// .envファイルの読み込み
require_once __DIR__ . '/../vendor/autoload.php';
(new \Dotenv\Dotenv(__DIR__ . '/..'))->load();

// ** MySQL 設定 - この情報はホスティング先から入手してください。 ** //
/** WordPress のためのデータベース名 */
define('DB_NAME', getenv('DB_NAME'));

/** MySQL データベースのユーザー名 */
define('DB_USER', getenv('DB_USER'));

/** MySQL データベースのパスワード */
define('DB_PASSWORD', getenv('DB_PASSWORD'));

/** MySQL のホスト名 */
define('DB_HOST', getenv('DB_HOST'));

// (以下に続く・・・)

まとめ

dotenvを利用することで、サーバごとに設定が異なる値や機密情報を安全に扱うことができました。冒頭で説明したように、他の言語でも使われている共通な記述になるので、覚えておいて損はないと思います。