PHP
CodeIgniter
CodeIgniter4

CodeIgniter4 の 環境/環境変数/設定 (Config) の使い方

More than 1 year has passed since last update.

CodeIgniter4 メモ。
CodeIgniter4 User Guide を参考にしながら、必要に応じてソースを読み解き、挙動を追って理解を深めようと思います。

Attention

2017/09/23 現在 開発版の CodeIgniter4 についての記事です。リリースまでに変更される可能性があることをご承知おきの上、お読み下さい。

使用している commit: 8eba1da1f194e5124d87cc4d3b5c75e68af1ad44

TL;DR

  • .envCI_ENVIRONMENT を設定しない。
  • 環境に依存する Config 以下の設定は .env に設定する

環境 (Environment)

User Guide: Handling Multiple Environments

環境を CodeIgniter に伝えるには、次の二つがあります。

  1. .env ファイルに記述
  2. Webサーバーに環境変数を設定
    • Apache であれば SetEnv CI_ENVIRONMENT development
    • nginx であれば fastcgi_param CI_ENVIRONMENT development

この CI_ENVIRONMENT は、下記で 定数 ENVIRONMENT に設定されます。

framework/system/CodeIgniter.php
    protected function detectEnvironment()
    {
        // running under Continuous Integration server?
        if (getenv('CI') !== false)
        {
            define('ENVIRONMENT', 'testing');
        }
        else
        {
            define('ENVIRONMENT', $_SERVER['CI_ENVIRONMENT'] ?? 'production');
        }
    }

CI_ENVIRONMENT が設定されていなければ、production として動作します。
ちなみに、getenv('CI') の CI とは、CodeIgniter ではなく、Continuous Integration の意味ですね。framework/.travis.yml に設定されていました。

.env と Web サーバー、どちらが優先される?

Apache/nginx 等の Web サーバーに設定された環境変数は、PHP では $_SERVER に格納され、使用できますが、.env にも CI_ENVIRONMENT を設定していた場合、どちらが優先されるのでしょう?

実際に環境変数をセットしているのは、下記の箇所です。

framework/system/Config/Dotenv.php
    protected function setVariable(string $name, string $value = '')
    {
        list($name, $value) = $this->normaliseVariable($name, $value);

        if ( ! getenv($name, true))
            putenv("$name=$value");
        if (empty($_ENV[$name]))
            $_ENV[$name] = $value;
        if (empty($_SERVER[$name]))
            $_SERVER[$name] = $value;
    }

$_ENV, $_SERVER それぞれ、その環境変数名が空だったら、値をセットするようになっています。なので、 Web サーバーの設定値が優先されます。

.env に書いてあるのに、環境が切り替わらない〜」 とハマらないためにも、どこで設定するかのルールを決めた方がよいでしょう。

追記

User Guide に書いてありましたね。

If the variable exists in the environment already, it will NOT be overwritten.

意訳

すでに環境変数が設定されていたら、変数は上書きしません。

追記ここまで

どの方法で CI_ENVIRONMENT を設定するか?

ここでは、本番・ステージング・ローカル開発の3つを切り替えたいと思います。

今や仮想化、コンテナ、Infrastructure as Code があるため、本番とステージングの構成に差異は無いという前提にします。

本番 (production)

$_SERVER['CI_ENVIRONMENT'] が設定されていなければ、production として扱うため、何も設定しません。

本番環境は、「しなくていいことは極力しない」ほうが良いと考えています。

ステージング (staging)

前述のとおり、本番と差はありません。ですが、後述のローカル開発環境との兼ね合いで、.envには書きたくありません。

なので、ここは Web サーバーに任せようと思います。

.htaccess に書くのも手ではありますが、nginx になると使えません。なので、もうサーバーの設定ファイルに書くことにします。

/etc/httpd/conf.d/apache_staging.conf
SetEnv CI_ENVIRONMENT development
/etc/nginx/conf.d/nginx_staging.conf
fastcgi_param CI_ENVIRONMENT "development";

専用のサーバーを設置していると思うので、グローバルなスコープで定義してしまいます。
これらのファイルをサーバー構築時に設置するだけでよいので、最もお手軽かと。

ローカル開発 (development)

CodeIgniter4 にはローカル開発環境のための serve スクリプトが付属しています。

php serve

と実行すると、ビルトインサーバーを使って http://localhost:8080/ で動作します。
この時、ルータースクリプトとして、rewrite.php を指定されており、その中で

$_SERVER['CI_ENVIRONMENT'] = 'development';

と、 CI_ENVIRONMENT が設定されています。.env に書きたくない、というのはココにあります。

前述の

$_ENV, $_SERVER それぞれ、その環境変数名が空だったら、値をセットするようになっています。なので、 Web サーバーの設定値が優先されます。

を思い出して下さい。そうです、$_SERVER['CI_ENVIRONMENT'] には値がセットされているので、.envCI_ENVIRONMENT を設定しても、development となります。

仮に、.envCI_ENVIRONMENT = "hoge" として serve から起動した場合、

var_dump($_SERVER['CI_ENVIRONMENT']); // "development"
var_dump($_ENV['CI_ENVIRONMENT'] // "hoge"

という、チグハグな状態になります。作りとしては、これら二値は同じ値であることが前提と思われるので、この運用はよろしくない。
いずれの環境においても、.envCI_ENVIRONMENT を設定しない
とするのが正のように思います。


設定 (Config)

User Guide: Working With Configuration Files

User Guide に従い、データベースの設定を読み出してみます

$db_config = new \Config\Database();
var_dump($db_config);
object(Config\Database)[40]
  public 'filesPath' => string '/XXX/XXX/XXX/application/Database/' (length=47)
  public 'defaultGroup' => string 'default' (length=7)
  public 'default' => 
    array (size=19)
      'DSN' => string '' (length=0)
      'hostname' => string 'localhost' (length=9)
      'username' => string '' (length=0)
      'password' => string '' (length=0)
      'database' => string '' (length=0)
      'DBDriver' => string 'MySQLi' (length=6)
      'DBPrefix' => string '' (length=0)
      'pConnect' => boolean false
      'DBDebug' => boolean true
      'cacheOn' => boolean false
      'cacheDir' => string '' (length=0)
      'charset' => string 'utf8' (length=4)
      'DBCollat' => string 'utf8_general_ci' (length=15)
      'swapPre' => string '' (length=0)
      'encrypt' => boolean false
      'compress' => boolean false
      'strictOn' => boolean false
      'failover' => 
        array (size=0)
          empty
      'port' => int 3306
  public 'tests' => 
    array (size=19)
      'DSN' => string '' (length=0)
      'hostname' => string '127.0.0.1' (length=9)
      'username' => string '' (length=0)
      'password' => string '' (length=0)
      'database' => string '' (length=0)
      'DBDriver' => string '' (length=0)
      'DBPrefix' => string 'db_' (length=3)
      'pConnect' => boolean false
      'DBDebug' => boolean true
      'cacheOn' => boolean false
      'cacheDir' => string '' (length=0)
      'charset' => string 'utf8' (length=4)
      'DBCollat' => string 'utf8_general_ci' (length=15)
      'swapPre' => string '' (length=0)
      'encrypt' => boolean false
      'compress' => boolean false
      'strictOn' => boolean false
      'failover' => 
        array (size=0)
          empty
      'port' => int 3306
  protected 'registrars' => null

application/Config/Database.php の値が取得できています。というか、クラスまんまですね。

User Guide によれば、自作の設定ファイルを作ることができるそうです。以下 User Guide から引用。

application/Config/App.php
<?php namespace Config;

class App extends \CodeIgniter\Config\BaseConfig {

        public $siteName = 'My Great Site';
        public $siteEmail = 'webmaster@example.com';

}

ただし、 application/Config/App.php, \Config\App はデフォルトで用意されていて、コアで使われているので別の名前にする必要があります。(User Guide も違う例文にしたほうが良いと思う…)

さらに、特に影響のない範囲ですが、デフォルトの Config では use CodeIgniter\Config\BaseConfig; しています。できれば前へ倣えしたほうがいいかと。

環境ごとの設定

どの環境でも同じ設定値で済むものについては、application/Config/ 以下に設定していけばよいですが、先述のデータベースなどは、本番と開発で接続先が異なることがほとんどです。

その取り回しについては、前項 環境 (Environment) で言及している .env が使えます。

CI_ENVIRONMENT.env に設定しないことを決めましたが、他方、設定値についてはとても有用です。

単純な使い方として、

.env
HOGE_VAR=hoge
$hoge_var = getenv('HOGE_VAR');
$hoge_var = $_SERVER['HOGE_VAR'];
$hoge_var = $_ENV['HOGE_VAR'];

というふうに使えるよう、環境変数にセットされます。

ここで紹介したい、便利な使い方は、.env から Config に値を設定する方法です。(もちろん、User Guide に書いてありますが)

データベースの接続設定を例にします。

.env
# Database
database.default.hostname = "localhost"
database.default.port = "3306"
database.default.username = "mysql_user"
database.default.password = "mysql_pass"
database.default.database = "app_db"
database.default.DBDriver = "MySQLi"

application/Config/Database.php についてはデフォルトのまま変更せず、先ほどと同じように設定値を var_dump してみます。 (長いので $db_config->default のみ抜粋)

array (size=19)
  'DSN' => string '' (length=0)
  'hostname' => string 'localhost' (length=9)
  'username' => string 'mysql_user' (length=10)
  'password' => string 'mysql_pass' (length=10)
  'database' => string 'app_db' (length=6)
  'DBDriver' => string 'MySQLi' (length=6)
  'DBPrefix' => string '' (length=0)
  'pConnect' => boolean false
  'DBDebug' => boolean true
  'cacheOn' => boolean false
  'cacheDir' => string '' (length=0)
  'charset' => string 'utf8' (length=4)
  'DBCollat' => string 'utf8_general_ci' (length=15)
  'swapPre' => string '' (length=0)
  'encrypt' => boolean false
  'compress' => boolean false
  'strictOn' => boolean false
  'failover' => 
    array (size=0)
      empty
  'port' => string '3306' (length=4)

ご覧の通り、値が変わりました。. でつなげてネストすることで、配列の値が設定されます。

あとは、本番、開発などの環境ごとに .env が変わればよいわけですね。

環境変数に値を設定することもできるし、CodeIgniter の Config の値を設定することもできるので、たとえば AWS などのサービスで使う 取扱いに注意しなければならないキーやパスワード.env ひとつにまとめることができます。

当然のことながら、この .env は バージョン管理に含めてはならない運用が必要です。

application/Config/*.php を編集する必要

.env で設定を管理するにしても、デフォルトで用意されていない値の場合、そのクラスのプロパティは宣言しておくとよいでしょう。たとえば、Apphoge という設定を作るとします。

app.hoge = "HogeHoge"

.env はこれでいいとして、\Config\App にも hoge を追加しましょう。

application/Config/App.php
<?php namespace Config;

use CodeIgniter\Config\BaseConfig;

class App extends BaseConfig
{
// ...略...
    public $hoge = 'default';
// ...略...
}

確実に .env に設定する ことが保証されるなら、問題はありません。しかし、前述のとおりバージョン管理に含めないので、プロパティを追加することで 「どんな設定値を追加したか」 のログができます。
デフォルト値も設定しておけば、フェイルセーフとして機能するかもしれません。

また、IDEがプロパティがあることを認識するので、補完が効くようになります。


まとめ

以上、CodeIgniter4 での環境切替/設定の取り回しについてまとめてみました。

先日 参加させていただいた CodeIgniter Night (第4回) で聞いた、「User Guide に書かれていることがすべて」 のとおりで、この記事は結局 User Guide の焼き直しみたいなものでした。

しかし、CodeIgniter はだいぶ自由度が高い印象を受けます。なので、自分が考える 「きれいな」 とか 「安全な」 開発運用のため、必要と思ったのでまとめた次第です。
これから CodeIgniter を使う誰かの一助にでもなれば。