[PHP]parse_ini_file関数の使い方を完全解説!設定ファイルを読み込む方法

PHP

はじめに

PHPでアプリケーションを開発する際、設定情報を外部ファイルで管理したいと思ったことはありませんか?

データベース接続情報、APIキー、アプリケーション設定など、コードとは分離して管理したい情報は多くあります。そんな時に便利なのがINI形式の設定ファイルです。

その設定ファイルを読み込むのが**parse_ini_file関数**です。この関数を使えば、シンプルで読みやすいINI形式の設定ファイルを簡単にPHPの配列として読み込めます。

この記事では、parse_ini_fileの基本から実践的な活用方法まで、詳しく解説します。

parse_ini_fileとは?

parse_ini_fileは、INI形式の設定ファイルを解析してPHPの配列として返す関数です。

基本構文

parse_ini_file(
    string $filename,
    bool $process_sections = false,
    int $scanner_mode = INI_SCANNER_NORMAL
): array|false

パラメータ

  • $filename: INIファイルのパス
  • $process_sections: セクションを処理するか(デフォルト: false
  • $scanner_mode: スキャナーモード
    • INI_SCANNER_NORMAL – デフォルト
    • INI_SCANNER_RAW – 値を加工しない
    • INI_SCANNER_TYPED – 型を保持(PHP 5.6.1以降)

戻り値

  • 成功時: 連想配列
  • 失敗時: false

INIファイルの基本フォーマット

; コメント(セミコロンで開始)
# これもコメント

; キー = 値
app_name = "My Application"
debug = true
max_connections = 100

; セクション

[database]

host = localhost port = 3306 username = root password = secret

[email]

smtp_host = smtp.example.com smtp_port = 587

対応バージョン

  • PHP 4.0.0 以降で使用可能
  • INI_SCANNER_TYPEDはPHP 5.6.1以降

基本的な使い方

シンプルな設定ファイルの読み込み

<?php
// config.ini
// app_name = "My App"
// debug = true
// max_users = 100

$config = parse_ini_file('config.ini');

if ($config === false) {
    die("設定ファイルの読み込みに失敗しました\n");
}

echo "アプリ名: {$config['app_name']}\n";
echo "デバッグ: " . ($config['debug'] ? 'ON' : 'OFF') . "\n";
echo "最大ユーザー数: {$config['max_users']}\n";

// 出力:
// アプリ名: My App
// デバッグ: ON
// 最大ユーザー数: 100
?>

セクション付きファイルの読み込み

<?php
// config.ini
// [app]
// name = "My App"
// version = "1.0.0"
//
// [database]
// host = localhost
// port = 3306

// セクションを処理する
$config = parse_ini_file('config.ini', true);

echo "アプリ名: {$config['app']['name']}\n";
echo "DBホスト: {$config['database']['host']}\n";
echo "DBポート: {$config['database']['port']}\n";

// 出力:
// アプリ名: My App
// DBホスト: localhost
// DBポート: 3306
?>

型を保持した読み込み

<?php
// config.ini
// string_value = "hello"
// int_value = 123
// float_value = 3.14
// bool_true = true
// bool_false = false
// null_value = null

$config = parse_ini_file('config.ini', false, INI_SCANNER_TYPED);

var_dump($config);

// 出力:
// array(6) {
//   ["string_value"]=> string(5) "hello"
//   ["int_value"]=> int(123)
//   ["float_value"]=> float(3.14)
//   ["bool_true"]=> bool(true)
//   ["bool_false"]=> bool(false)
//   ["null_value"]=> NULL
// }
?>

実践的な使用例

例1: 設定クラスの実装

<?php
class Config {
    private static $config = null;
    private static $file_path = null;
    
    /**
     * 設定ファイルを読み込み
     */
    public static function load($file_path) {
        if (!file_exists($file_path)) {
            throw new RuntimeException("設定ファイルが見つかりません: {$file_path}");
        }
        
        self::$file_path = $file_path;
        self::$config = parse_ini_file($file_path, true, INI_SCANNER_TYPED);
        
        if (self::$config === false) {
            throw new RuntimeException("設定ファイルの解析に失敗しました");
        }
    }
    
    /**
     * 設定値を取得
     */
    public static function get($key, $default = null) {
        if (self::$config === null) {
            throw new RuntimeException("設定ファイルがロードされていません");
        }
        
        // ドット記法をサポート(例: "database.host")
        $keys = explode('.', $key);
        $value = self::$config;
        
        foreach ($keys as $k) {
            if (!isset($value[$k])) {
                return $default;
            }
            $value = $value[$k];
        }
        
        return $value;
    }
    
    /**
     * セクション全体を取得
     */
    public static function getSection($section) {
        if (self::$config === null) {
            throw new RuntimeException("設定ファイルがロードされていません");
        }
        
        return self::$config[$section] ?? [];
    }
    
    /**
     * すべての設定を取得
     */
    public static function all() {
        return self::$config ?? [];
    }
    
    /**
     * 設定値が存在するかチェック
     */
    public static function has($key) {
        try {
            $value = self::get($key);
            return $value !== null;
        } catch (RuntimeException $e) {
            return false;
        }
    }
    
    /**
     * 必須の設定値を取得(存在しない場合は例外)
     */
    public static function require($key) {
        $value = self::get($key);
        
        if ($value === null) {
            throw new RuntimeException("必須の設定 '{$key}' が見つかりません");
        }
        
        return $value;
    }
}

// 使用例(config.ini)
/*

[app]

name = “My Application” debug = true timezone = “Asia/Tokyo”

[database]

host = localhost port = 3306 username = root password = secret database = myapp

[cache]

enabled = true driver = redis ttl = 3600 */ // 設定をロード Config::load(‘config.ini’); // 設定値を取得 echo “アプリ名: ” . Config::get(‘app.name’) . “\n”; echo “DBホスト: ” . Config::get(‘database.host’) . “\n”; echo “キャッシュTTL: ” . Config::get(‘cache.ttl’, 1800) . “\n”; // セクション全体を取得 $db_config = Config::getSection(‘database’); print_r($db_config); // 必須設定のチェック try { $api_key = Config::require(‘api.key’); } catch (RuntimeException $e) { echo “エラー: ” . $e->getMessage() . “\n”; } ?>

例2: 環境別設定の管理

<?php
class EnvironmentConfig {
    private $config;
    private $environment;
    
    public function __construct($base_config_dir, $environment = null) {
        // 環境を決定
        $this->environment = $environment ?? getenv('APP_ENV') ?? 'production';
        
        // ベース設定を読み込み
        $base_file = $base_config_dir . '/config.ini';
        $this->config = $this->loadConfig($base_file);
        
        // 環境固有の設定を読み込み(存在する場合)
        $env_file = $base_config_dir . "/config.{$this->environment}.ini";
        if (file_exists($env_file)) {
            $env_config = $this->loadConfig($env_file);
            $this->config = $this->mergeConfig($this->config, $env_config);
        }
    }
    
    private function loadConfig($file) {
        if (!file_exists($file)) {
            throw new RuntimeException("設定ファイルが見つかりません: {$file}");
        }
        
        $config = parse_ini_file($file, true, INI_SCANNER_TYPED);
        
        if ($config === false) {
            throw new RuntimeException("設定ファイルの解析に失敗: {$file}");
        }
        
        return $config;
    }
    
    private function mergeConfig($base, $override) {
        foreach ($override as $key => $value) {
            if (is_array($value) && isset($base[$key]) && is_array($base[$key])) {
                $base[$key] = $this->mergeConfig($base[$key], $value);
            } else {
                $base[$key] = $value;
            }
        }
        
        return $base;
    }
    
    public function get($key, $default = null) {
        $keys = explode('.', $key);
        $value = $this->config;
        
        foreach ($keys as $k) {
            if (!isset($value[$k])) {
                return $default;
            }
            $value = $value[$k];
        }
        
        return $value;
    }
    
    public function getEnvironment() {
        return $this->environment;
    }
}

// 使用例

// config.ini(ベース設定)
/*

[app]

name = “My App” debug = false

[database]

host = localhost port = 3306 */ // config.development.ini(開発環境) /*

[app]

debug = true

[database]

host = localhost username = dev_user password = dev_pass */ // config.production.ini(本番環境) /*

[database]

host = db.example.com username = prod_user password = prod_pass */ // 環境に応じて設定をロード $config = new EnvironmentConfig(‘./config’, ‘development’); echo “環境: ” . $config->getEnvironment() . “\n”; echo “デバッグ: ” . ($config->get(‘app.debug’) ? ‘ON’ : ‘OFF’) . “\n”; echo “DBホスト: ” . $config->get(‘database.host’) . “\n”; ?>

例3: 設定ファイルのバリデーション

<?php
class ConfigValidator {
    private $config;
    private $errors = [];
    
    public function __construct($config_file) {
        $this->config = parse_ini_file($config_file, true, INI_SCANNER_TYPED);
        
        if ($this->config === false) {
            throw new RuntimeException("設定ファイルの読み込みに失敗しました");
        }
    }
    
    /**
     * 必須キーをチェック
     */
    public function requireKeys($section, $keys) {
        if (!isset($this->config[$section])) {
            $this->errors[] = "セクション '{$section}' が見つかりません";
            return $this;
        }
        
        foreach ($keys as $key) {
            if (!isset($this->config[$section][$key])) {
                $this->errors[] = "必須キー '{$section}.{$key}' が見つかりません";
            }
        }
        
        return $this;
    }
    
    /**
     * 値の型をチェック
     */
    public function validateType($section, $key, $expected_type) {
        if (!isset($this->config[$section][$key])) {
            return $this;
        }
        
        $value = $this->config[$section][$key];
        $actual_type = gettype($value);
        
        if ($actual_type !== $expected_type) {
            $this->errors[] = "'{$section}.{$key}' の型が不正です(期待: {$expected_type}, 実際: {$actual_type})";
        }
        
        return $this;
    }
    
    /**
     * 値の範囲をチェック
     */
    public function validateRange($section, $key, $min, $max) {
        if (!isset($this->config[$section][$key])) {
            return $this;
        }
        
        $value = $this->config[$section][$key];
        
        if (!is_numeric($value)) {
            $this->errors[] = "'{$section}.{$key}' は数値ではありません";
        } elseif ($value < $min || $value > $max) {
            $this->errors[] = "'{$section}.{$key}' の値が範囲外です({$min}~{$max})";
        }
        
        return $this;
    }
    
    /**
     * 値の選択肢をチェック
     */
    public function validateChoice($section, $key, $choices) {
        if (!isset($this->config[$section][$key])) {
            return $this;
        }
        
        $value = $this->config[$section][$key];
        
        if (!in_array($value, $choices, true)) {
            $choices_str = implode(', ', $choices);
            $this->errors[] = "'{$section}.{$key}' の値が不正です(選択肢: {$choices_str})";
        }
        
        return $this;
    }
    
    /**
     * バリデーション結果をチェック
     */
    public function validate() {
        if (!empty($this->errors)) {
            $error_list = implode("\n  - ", $this->errors);
            throw new RuntimeException(
                "設定ファイルのバリデーションに失敗しました:\n  - {$error_list}"
            );
        }
        
        return $this->config;
    }
    
    /**
     * エラーを取得
     */
    public function getErrors() {
        return $this->errors;
    }
}

// 使用例
try {
    $validator = new ConfigValidator('config.ini');
    
    $config = $validator
        // 必須キーをチェック
        ->requireKeys('app', ['name', 'version'])
        ->requireKeys('database', ['host', 'port', 'username', 'password'])
        
        // 型をチェック
        ->validateType('app', 'debug', 'boolean')
        ->validateType('database', 'port', 'integer')
        
        // 範囲をチェック
        ->validateRange('database', 'port', 1, 65535)
        ->validateRange('cache', 'ttl', 0, 86400)
        
        // 選択肢をチェック
        ->validateChoice('app', 'environment', ['development', 'staging', 'production'])
        ->validateChoice('cache', 'driver', ['file', 'redis', 'memcached'])
        
        // バリデーション実行
        ->validate();
    
    echo "✓ 設定ファイルは正常です\n";
    
} catch (RuntimeException $e) {
    echo "エラー: " . $e->getMessage() . "\n";
}
?>

例4: 設定ファイルのキャッシング

<?php
class CachedConfig {
    private $config_file;
    private $cache_file;
    private $config;
    
    public function __construct($config_file, $cache_dir = null) {
        $this->config_file = $config_file;
        
        // キャッシュファイルのパスを生成
        $cache_dir = $cache_dir ?? sys_get_temp_dir();
        $cache_name = md5($config_file) . '.cache';
        $this->cache_file = $cache_dir . '/' . $cache_name;
        
        $this->load();
    }
    
    private function load() {
        // キャッシュが有効かチェック
        if ($this->isCacheValid()) {
            $this->loadFromCache();
        } else {
            $this->loadFromFile();
            $this->saveToCache();
        }
    }
    
    private function isCacheValid() {
        if (!file_exists($this->cache_file)) {
            return false;
        }
        
        $cache_time = filemtime($this->cache_file);
        $config_time = filemtime($this->config_file);
        
        // 設定ファイルがキャッシュより新しい場合は無効
        return $cache_time >= $config_time;
    }
    
    private function loadFromFile() {
        $this->config = parse_ini_file($this->config_file, true, INI_SCANNER_TYPED);
        
        if ($this->config === false) {
            throw new RuntimeException("設定ファイルの読み込みに失敗しました");
        }
    }
    
    private function loadFromCache() {
        $cache_data = file_get_contents($this->cache_file);
        $this->config = unserialize($cache_data);
    }
    
    private function saveToCache() {
        $cache_data = serialize($this->config);
        file_put_contents($this->cache_file, $cache_data);
    }
    
    public function get($key, $default = null) {
        $keys = explode('.', $key);
        $value = $this->config;
        
        foreach ($keys as $k) {
            if (!isset($value[$k])) {
                return $default;
            }
            $value = $value[$k];
        }
        
        return $value;
    }
    
    public function clearCache() {
        if (file_exists($this->cache_file)) {
            unlink($this->cache_file);
        }
    }
}

// 使用例
$config = new CachedConfig('config.ini');

// 1回目: ファイルから読み込み(遅い)
$start = microtime(true);
$value1 = $config->get('database.host');
$time1 = microtime(true) - $start;

// 2回目: キャッシュから読み込み(速い)
$config2 = new CachedConfig('config.ini');
$start = microtime(true);
$value2 = $config2->get('database.host');
$time2 = microtime(true) - $start;

echo "1回目: " . number_format($time1 * 1000, 3) . "ms\n";
echo "2回目: " . number_format($time2 * 1000, 3) . "ms\n";
echo "高速化: " . number_format($time1 / $time2, 2) . "倍\n";
?>

例5: 設定ファイルの自動生成

<?php
class ConfigGenerator {
    /**
     * 配列からINIファイルを生成
     */
    public static function generate($config, $file_path, $header = null) {
        $ini_content = '';
        
        // ヘッダーコメント
        if ($header) {
            $ini_content .= "; {$header}\n";
            $ini_content .= "; Generated: " . date('Y-m-d H:i:s') . "\n\n";
        }
        
        foreach ($config as $section => $values) {
            if (is_array($values)) {
                // セクション
                $ini_content .= "[{$section}]\n";
                
                foreach ($values as $key => $value) {
                    $ini_content .= self::formatKeyValue($key, $value);
                }
                
                $ini_content .= "\n";
            } else {
                // セクションなしのキー
                $ini_content .= self::formatKeyValue($section, $values);
            }
        }
        
        // ファイルに書き込み
        if (file_put_contents($file_path, $ini_content) === false) {
            throw new RuntimeException("設定ファイルの書き込みに失敗しました");
        }
        
        return true;
    }
    
    private static function formatKeyValue($key, $value) {
        if (is_bool($value)) {
            $value_str = $value ? 'true' : 'false';
        } elseif (is_null($value)) {
            $value_str = 'null';
        } elseif (is_string($value)) {
            // 特殊文字を含む場合はクォート
            if (preg_match('/[;#\s]/', $value)) {
                $value_str = '"' . addslashes($value) . '"';
            } else {
                $value_str = $value;
            }
        } else {
            $value_str = (string)$value;
        }
        
        return "{$key} = {$value_str}\n";
    }
    
    /**
     * 設定のテンプレートを生成
     */
    public static function generateTemplate($file_path) {
        $template = [
            'app' => [
                'name' => 'My Application',
                'version' => '1.0.0',
                'debug' => false,
                'timezone' => 'UTC'
            ],
            'database' => [
                'host' => 'localhost',
                'port' => 3306,
                'username' => 'root',
                'password' => '',
                'database' => 'myapp'
            ],
            'cache' => [
                'enabled' => true,
                'driver' => 'file',
                'ttl' => 3600
            ]
        ];
        
        return self::generate(
            $template,
            $file_path,
            'Application Configuration Template'
        );
    }
}

// 使用例1: 配列から生成
$config = [
    'app' => [
        'name' => 'My App',
        'debug' => true
    ],
    'database' => [
        'host' => 'localhost',
        'port' => 3306
    ]
];

ConfigGenerator::generate($config, 'generated_config.ini', 'My Application Config');

// 使用例2: テンプレート生成
ConfigGenerator::generateTemplate('config.template.ini');

echo "設定ファイルを生成しました\n";
?>

INIファイルのフォーマット

基本的な書き方

; コメント行

; 文字列
app_name = "My Application"
description = Hello World

; 数値
port = 8080
timeout = 30.5

; ブール値
debug = true
enabled = On
disabled = Off

; NULL
value = null

; 配列(PHPの配列として解釈)
colors[] = red
colors[] = green
colors[] = blue

; セクション

[database]

host = localhost port = 3306

エスケープと特殊文字

; クォートで囲む
path = "C:\Program Files\MyApp"
message = "Hello \"World\""

; 複数行(PHPでは1行として扱われる)
long_text = "This is a very \
long text that spans \
multiple lines"

まとめ

parse_ini_fileは、INI形式の設定ファイルを読み込む関数です。

主な特徴:

  • ✅ シンプルで読みやすいINI形式をサポート
  • ✅ セクション分けが可能
  • ✅ 型を保持した読み込みに対応
  • ✅ コメントをサポート

使用場面:

  • アプリケーション設定の管理
  • 環境別設定ファイル
  • データベース接続情報
  • API設定

関連関数:

  • parse_ini_string() – 文字列からINIを解析
  • get_cfg_var() – PHP設定を取得

ベストプラクティス:

  • 機密情報はパーミッション設定に注意
  • 環境別に設定ファイルを分ける
  • バリデーションを実装
  • キャッシングでパフォーマンス向上

セキュリティ注意点:

  • INIファイルはWebルート外に配置
  • パーミッションを適切に設定(600または640)
  • パスワードなど機密情報は環境変数も検討
  • バージョン管理から除外(.gitignoreに追加)

この関数を理解して、保守性の高い設定管理を実現しましょう!

参考リンク


この記事が役に立ったら、ぜひシェアしてください!

タイトルとURLをコピーしました