PHPの整数型は32ビットOSでは符号付き32bit整数、64ビットOSでは符号付き64bit整数となる。この範囲を超える整数を取り扱う場合で演算が必要な場合はGMP整数を利用する。1)これはデータベースなど、任意精度型のデータ型をサポートしている外部システムを利用する場合に特に重要である。
PHPには任意精度型整数(無限精度整数)を取り扱えるBCMathとGMPモジュールがある。BCMathはデフォルトでコンパイルされ常に利用可能であるが、GMPモールはデフォルトで+-/*%などの演算オペレータが利用できる。GMPモジュールを利用した演算は将来的にデフォルトで利用できるようになる可能性が高い。このため可能な場合はGMPモジュールの利用が好ましい。
現在のPHPは任意精度の浮動小数点型をサポートする機能は持っていない。
ここではRDBMSのPostgreSQLを例として利用する。しかし、任意精度型を持つシステム(PHPを含む)の場合は出力先のデータ型と整合性が保てることに注意しなければならない。非適合コード、適合コードは以下のテーブル定義を持つデータベースとする。
CREATE TABLE sample ( id SERIAL NOT NULL, -- SERIAL is signed 32 bit integer int8 INT8, -- INT8 is signed 64 bit integer num NUMERIC(100, 0) -- 整数100桁 );
非適合コードを実行してもエラーにはならない。これは符号付き64ビット整数がオーバーフローした場合に自動的に浮動小数点型に変換されるからである。実際には浮動小数点型で表現可能な範囲まで丸められて不正確な値が保存される。
<?php // This code is for 64 bit OS $db = pg_connect('host=localhost'); if (!$db) { throw new Exception('Cannot connect to database'); } $myint = 1234567890*1234567890000000; // Exceeds signed 64 bit integer range. $sql = 'INSERT INTO sample (num) VALUES ($1)'; $ret = pg_query_params($sql, [$myint]); if ($ret === FALSE) { throw new Exception('Query failed'); } ?>
<?php // This code is for 64 bit OS $db = pg_connect('host=localhost'); if (!$db) { throw new Exception('Cannot connect to database'); } // GMP整数に変換して精度を保つ $x = gmp_init(1234567890); $y = gmp_init(1234567890000000); $myint = $x*$y; // Exceeds signed 64 bit integer range. $sql = 'INSERT INTO sample (num) VALUES ($1)'; $ret = pg_query_params($sql, [$myint]); if ($ret === FALSE) { throw new Exception('Query failed'); } ?>
浮動小数点型で表現可能な値に丸められても問題にならない場合は適用しなくてよい。
保存されるデータが不完全となる。
| Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
| IDS05-J | medium | likely | medium | P4 | L3 |