INI 格式因結構簡單、人類可讀、多語言支援良好,常用於應用程式設定。PHP 內建 parse_ini_file() 讀取,但缺乏寫入功能。本文提供完整的讀寫封裝函式,支援區段、陣列值、空值處理,並說明跨語言(Python)互操作注意事項。
<?php
/**
* 將關聯陣列寫入 INI 檔案
* @param array $assocArr 資料陣列,支援多層區段
* @param string $path 檔案路徑
* @param bool $hasSections 是否包含區段(section)
* @return bool 成功與否
*/
function write_ini_file(array $assocArr, string $path, bool $hasSections = false): bool
{
$content = '';
if ($hasSections) {
foreach ($assocArr as $section => $keys) {
$content .= "[$section]\n";
foreach ($keys as $key => $val) {
$content .= writeIniValue($key, $val);
}
}
} else {
foreach ($assocArr as $key => $val) {
$content .= writeIniValue($key, $val);
}
}
$handle = @fopen($path, 'w');
if (!$handle) return false;
$result = fwrite($handle, $content);
fclose($handle);
return $result !== false;
}
/** 統一處理值的輸出格式:字串加雙引號、陣列展開、空值處理 */
function writeIniValue(string $key, $val): string
{
if (is_array($val)) {
$lines = '';
foreach ($val as $item) {
$lines .= "$key[] = \"$item\"\n";
}
return $lines;
}
if ($val === '') {
return "$key = \n";
}
return "$key = \"$val\"\n";
}
?>
<?php
$sampleData = [
'database' => [
'host' => 'localhost',
'port' => 3306,
'name' => 'myapp',
'user' => 'root',
'pass' => 'secret',
],
'cache' => [
'driver' => 'redis',
'servers' => ['127.0.0.1:6379', '127.0.0.1:6380'], // 陣列值
],
'debug' => true,
];
write_ini_file($sampleData, __DIR__ . '/config.ini', true); // true = 有區段
?>
[database]
host = "localhost"
port = "3306"
name = "myapp"
user = "root"
pass = "secret"
[cache]
driver = "redis"
servers[] = "127.0.0.1:6379"
servers[] = "127.0.0.1:6380"
debug = "1"
<?php
/**
* 讀取 INI 並回傳關聯陣列
* @param string $name 檔案名稱(相對路徑)
* @return array|false
*/
public function readIni(string $name)
{
$path = SEM_PATH . 'init/' . $name; // 專案常數路徑
if (!is_file($path)) return false;
// 第二參數 true = 解析區段為多維陣列
$data = parse_ini_file($path, true);
return $data ?: false;
}
?>
PHP write_ini_file 產出的值一律雙引號包裹(如 port = "3306")。Python 標準庫 configparser 預設不處理引號,會將引號視為值一部分,導致讀取到 "3306" 而非 3306。
import configparser, re
config = configparser.ConfigParser()
config.read('config.ini')
def strip_quotes(v):
return re.sub(r'^"(.*)"$', r'\1', v) # 移除首尾雙引號
for section in config.sections():
for key, val in config[section].items():
config[section][key] = strip_quotes(val)
| 面向 | 建議 |
|---|---|
| 編碼 | 檔案存 UTF-8 無 BOM,PHP parse_ini_file 預期 UTF-8 |
| 安全 | 設定檔放在 public/ 以外目錄,Nginx/Apache 禁止直接存取 *.ini |
| 版本控制 | config.ini.example 納入 Git,實際 config.ini 加入 .gitignore |
| 環境區隔 | 採 config.local.ini 覆蓋機制,或用環境變數注入敏感值 |
| 效能 | 啟動時一次性讀取快取至 APCu/Redis,避免每請求解析 |
symfony/yaml,結構更豐富、支援錨點參考,適合複雜設定。json_decode(file_get_contents(...), true),極速解析、原生支援巢狀陣列,但無註解。return [ ... ]; 純 PHP 檔案,include 即得陣列,效能最強、支援邏輯運算,但非通用格式。