INIファイルを間違って編集したことで、システム障害に至るケースに遭遇したので、これを期に自分が仕事で良く使っている言語におけるINIファイルのエラーの扱い方についてまとめた。
なお、現在INIファイルは https://ja.wikipedia.org/wiki/INI%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB によれば、規格化/標準化されていないらしい。
調査対象言語
Windows上で以下の言語とWin32 APIについて調査した。
言語とバージョン | ライブラリや関数 |
---|---|
PHP 7.4.22 (x64) | parse_ini_file |
Strawberry Perl 5.32.1 (x64) | Config::Tiny |
Python 3.7.9 (x86) | ConfigParser |
Ruby 2.7.2 (x64) | IniFile |
kernel32.dll 10.0.19041.1151 | GetPrivateProfileString |
スクリプト
PHP
test.php
<?php
if (count($argv) == 1) {
printf("usage: %s <inifile>\r\n", $argv[0]);
exit();
}
$ini = parse_ini_file($argv[1], true);
printf("%s\r\n", $ini['section']['key']);
?>
Perl
test.pl
use Config::Tiny;
if ($#ARGV < 0) {
print "usage: $0 <inifile>\n";
exit;
}
$ini = Config::Tiny->read($ARGV[0]);
if (!defined($ini)) {
print "undef\n";
exit;
}
printf("%s\n", $ini->{'section'}->{'key'});
Python
test.py
import configparser
import sys
if len(sys.argv) == 1:
print("usage: %s <inifile>" % (sys.argv[0]))
sys.exit()
ini = configparser.ConfigParser()
ini.read(sys.argv[1])
print(ini['section']['key'])
Ruby
test.rb
require 'inifile'
if ARGV.length == 0
puts "usage: #{$0} <inifile>"
exit
end
ini = IniFile.load(ARGV[0])
puts ini['section']['key']
Win32 API
コンパイルするのが面倒なので、PerlのWin32::APIを使用した。
testw.pl
use Win32::API;
if ($#ARGV < 0) {
print "usage: $0 <inifile>\n";
exit;
}
Win32::API->Import('kernel32',
'DWORD GetPrivateProfileString(
LPCTSTR appName, LPCTSTR keyName, LPCTSTR default,
LPTSTR returned, DWORD size, LPCTSTR fname)');
$fname = $ARGV[0];
$fname = ".\\$fname" if index($fname, '\\') < 0;
$value = ' ' x 100;
GetPrivateProfileString('section', 'key', '', $value, length($value), $fname);
$value = substr($value, 0, index($value, "\0"));
print "$value\n";
調査内容
以下の不正行とはコメント、セクション、キーと値のいずれでもない行のことである。
ケース1:ファイル先頭のセクション前の不正行
case1.ini
hoge
[section]
key=hello world
ケース2:セクション内の不正行
case2.ini
[section]
hoge
key=hello world
ケース3:キーと値を "==" で結合
case3.ini
[section]
key==hello world
ケース4:"#" によるコメント
case4.ini
#hoge
[section]
key=hello world
ケース5:値の後に ";" によるコメント
case5.ini
[section]
key="hello world" ;hoge
ケース6:値の後に "#" によるコメント
case6.ini
[section]
key="hello world" #hoge
調査結果
言語 | c1 | c2 | c3 | c4 | c5 | c6 |
---|---|---|---|---|---|---|
PHP | o | o | x | o | o | x |
Perl | x | x | o | o | x | x |
Python | x | x | o | o | x | x |
Ruby | x | x | o | o | o | o |
API | o | o | o | o | x | x |
- ケース1/2が○の場合、不正行は無視されて、値は「hello world」となった
- ケース3が○の場合、値は「=hello world」となった
- ケース4が○の場合、値は「hello world」となった
- ケース5/6が○の場合、値は「hello world」となった
- ケース5が×の場合、値は「"hello world" ;hoge」となった
- ケース6が×の場合、値はPHPが「hello world#hoge」、それ以外は「"hello world" #hoge」となった
総評
冒頭に記載した通り、ある設定行で "=" を "==" と間違って編集したため、他の大切な設定が読めなくなり、システム障害に至ったので、感情的になっているかも知れないが、以下のように総評する。
Win32 API以外の各種言語でINIファイルを扱う場合は特に、初期設定から変更しないものとそれ以外でINIファイルを分けるなど、対策を講じるように設計していただきたい。
- PHPは他の言語と真逆で、キーと値を "==" で結合するとsyntax errorとなった(腑に落ちない結果)
- Perl / Python / Rubyでは不正行はparse errorとなった(納得できる結果)
- Win32 APIでは不正行を無視してくれた(慣れ親しんだ結果)
- 値にコメントを含めない方が無難
以上