はじめに

Symfonyの Dotenvコンポーネント を使うと、.env というファイルに環境変数を定義しておくことで、アプリケーション内から getenv() $_ENV $_SERVER などを通してその環境変数にアクセスできるようになります。

Symfony 3.3以上ではフレームワークにビルトインされており、Syfmonyアプリケーションのdev環境では .env ファイルを使って環境変数を設定することができるようになっています。

この記事でお伝えすること

今回、.env ファイルで 値に改行文字を含む ような環境変数を設定したい状況に遭遇し、方法を調べましたので、小ネタですが記事として残しておきたいと思います。

結論

symfony/dotenvのテストコード を見てみたら、知りたいことがほぼ全て書かれていました :+1:

複数行に渡る文字列を1つの環境変数にセットしたい場合

結論としては、以下のようにすれば複数行に渡る文字列を1つの環境変数にセットできます。

FOO="a
b
c"

これで、FOO 環境変数に

a
b
c

という値がセットされます。

"" で囲む代わりに '' でも同じことができないのかな?と思い、テストケースの中にはなかったので手元で実験してみたところ、Missing quote to end the value というエラーになってダメでした。

さらにその中に \n という文字列を含ませたい場合

これはちょっとレアなケースかもしれませんが、例えば以下のような文字列を環境変数にセットしたい場合、少し話がややこしくなります。

{
  "private_key": "-----BEGIN PRIVATE KEY-----\naaaaa\nbbbbb\nccccc\nddddd\neeeee\n-----END PRIVATE KEY-----\n"
}

この場合、"\" とエスケープしなければならないのは分かるとしても、その上で先ほどのように単純に

JSON="{
  \"private_key\": \"-----BEGIN PRIVATE KEY-----\naaaaa\nbbbbb\nccccc\nddddd\neeeee\n-----END PRIVATE KEY-----\n\"
}"

としてしまうと、文字列の中に含まれる \n が展開されてしまい、JSON 環境変数の値は

{
  "private_key": "-----BEGIN PRIVATE KEY-----
aaaaa
bbbbb
ccccc
ddddd
eeeee
-----END PRIVATE KEY-----
"
}

となってしまいます。これではJSONとしてパースできません。\n は文字列として値の中に残したいのです。

文字列連結を使う

symfony/dotenvのテストケースのこの部分 を見ると、文字列の連結ができるようです。

また、この辺り を見る限り、""'' の使い分けは、PHPの文字列リテラルと同様、"" では \n が展開されて改行文字として出力され、'' では展開されずそのまま \n が出力されるようです。

というわけで、今回のケースでは以下のように書けば意図したとおりの文字列を環境変数にセットできます。

JSON="{
  \"private_key\": \"-----BEGIN PRIVATE KEY-----"'\n'"aaaaa"'\n'"bbbbb"'\n'"ccccc"'\n'"ddddd"'\n'"eeeee"'\n'"-----END PRIVATE KEY-----"'\n'"\"
}"

ちょっと分かりにくいですが、要するに以下の文字列を連結しているわけです。\n の部分のみ "" ではなく '' で囲んであるので、改行文字に展開されずにそのまま出力できるというわけです。

"{
  \"private_key\": \"-----BEGIN PRIVATE KEY-----"
'\n'
"aaaaa"
'\n'
"bbbbb"
'\n'
"ccccc"
'\n'
"ddddd"
'\n'
"eeeee"
'\n'
"-----END PRIVATE KEY-----"
'\n'
"\"
  }"

おわりに

最後に改めて結論をまとめておきます。

  • 複数行に渡る文字列を環境変数にセットしたい場合は、"" で囲んで普通に改行しちゃえばOK
  • 文字列中に " という文字列を含みたい場合は \" とエスケープする
  • 文字列中に \n という文字列を含みたい場合は、その前後で文字列を切って、\n だけは '' で囲む形にして、連結する
    • 実践的には、\n"'\n'" で一括置換すればOK

以上です。

小ネタでしたが、どこかで誰かのお役に立てば幸いです :raised_hands: