0
1

More than 3 years have passed since last update.

各種言語におけるINIファイルのエラー扱い

Last updated at Posted at 2021-08-22

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では不正行を無視してくれた(慣れ親しんだ結果)
  • 値にコメントを含めない方が無難

以上

0
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1