現在の言語: 日本語

戻る

乱数
乱数関連

PHPで乱数を取得する主な方法は、用途に合わせて以下の3つがあります。

random_int(最小値, 最大値)
暗号学的に強い乱数を生成します。

mt_rand(最小値, 最大値)
従来の rand() よりも高速で質の良い乱数を生成します。

Random\Randomizer
配列のシャッフルなども簡単に行えます。


[サンプル]

copy
use Random\Randomizer;
use Random\Engine\Secure;//セキュリティを重視する場合

class test1
{
	function test1()
	{
		$num = random_int(0, 9);
		echo $num.PHP_EOL;//ex.)9
	}

	function test2()
	{
		echo mt_rand(0, 9);//ex.)8
	}
	function test3()
	{
		// random_int() と同等の安全性を持つインスタンス
		$randomizer = new Randomizer(new Secure());
		echo $randomizer->getInt(0, 9);//ex.)6
	}
	function test4()
	{
		// 1. 0から9までの配列を作成
		$numbers = range(0, 9);
		
		// 2. Randomizerを使用してシャッフル(内部で安全なフィッシャー・イェーツを実行)
		$randomizer = new Randomizer();
		$shuffledNumbers = $randomizer->shuffleArray($numbers);
		
		print_r($shuffledNumbers);
		/*
		Array
		(
			[0] => 9
			[1] => 7
			[2] => 3
			[3] => 1
			[4] => 6
			[5] => 8
			[6] => 5
			[7] => 0
			[8] => 4
			[9] => 2
		)
		*/
	}
	function test5()
	{
		
		// 0から9までの配列で実行
		$numbers = range(0, 9);
		$shuffled = $this->fisherYatesShuffle($numbers);
		
		print_r($shuffled);
		/*
		Array
		(
			[0] => 8
			[1] => 5
			[2] => 2
			[3] => 1
			[4] => 7
			[5] => 3
			[6] => 6
			[7] => 0
			[8] => 4
			[9] => 9
		)
		*/
	}
	private function fisherYatesShuffle(array $items): array 
	{
		$count = count($items);
		
		// 配列の最後尾から手前に向かって処理
		for ($i = $count - 1; $i > 0; $i--) 
		{
			// 0から$iの間でランダムなインデックスを選択
			$j = random_int(0, $i);
			
			// 要素の入れ替え
			$temp = $items[$i];
			$items[$i] = $items[$j];
			$items[$j] = $temp;
		}
		
		return $items;
	}

}
echo "<pre>";
$cls1= new test1();
echo "[test1]".PHP_EOL;
$cls1->test1();
echo "[test2]".PHP_EOL;
$cls1->test2();
echo "[test3]".PHP_EOL;
$cls1->test3();
echo "[test4]".PHP_EOL;
$cls1->test4();
echo "[test5]".PHP_EOL;
$cls1->test5();

echo "</pre>";
copy
use Random\Randomizer;
use Random\Engine\Secure; // For security-conscious users

class test1
{
	function test1()
	{
		$num = random_int(0, 9);
		echo $num.PHP_EOL; // ex.)9
	}
	
	function test2()
	{
		echo mt_rand(0, 9); // ex.)8
	}
	function test3()
	{
		// Instance with the same security as random_int()
		$randomizer = new Randomizer(new Secure());
		echo $randomizer->getInt(0, 9); // ex.)6
	}
	function test4()
	{
		// 1. Create an array of numbers from 0 to 9
		$numbers = range(0, 9);
		
		// 2. Shuffle using Randomizer (performs secure Fisher-Yates internally)
		$randomizer = new Randomizer();
		$shuffledNumbers = $randomizer->shuffleArray($numbers);
		
		print_r($shuffledNumbers);
		/*
		Array
		(
		[0] => 9
		[1] => 7
		[2] => 3
		[3] => 1
		[4] => 6
		[5] => 8
		[6] => 5
		[7] => 0
		[8] => 4
		[9] => 2
		)
		*/
	}
	function test5()
	{
		
		// Run on an array from 0 to 9
		$numbers = range(0, 9);
		$shuffled = $this->fisherYatesShuffle($numbers);
		
		print_r($shuffled);
		/*
		Array
		(
		[0] => 8
		[1] => 5
		[2] => 2
		[3] => 1
		[4] => 7
		[5] => 3
		[6] => 6
		[7] => 0
		[8] => 4
		[9] => 9
		)
		*/
	}
	private function fisherYatesShuffle(array $items): array
	{
		$count = count($items);
		
		// Process from the end of the array to the front
		for ($i = $count - 1; $i > 0; $i--) 
		{
			// Select a random index between 0 and $i
			$j = random_int(0, $i);
			
			// Swap elements
			$temp = $items[$i];
			$items[$i] = $items[$j];
			$items[$j] ​​= $temp;
		}
	
		return $items;
	}

}
echo "<pre>";
$cls1 = new test1();
echo "[test1]".PHP_EOL;
$cls1->test1();
echo "[test2]".PHP_EOL;
$cls1->test2();
echo "[test3]".PHP_EOL;
$cls1->test3();
echo "[test4]".PHP_EOL;
$cls1->test4();
echo "[test5]".PHP_EOL;
$cls1->test5();

echo "</pre>";

mt_randの問題点
メルセンヌ・ツイスタは、過去に出力された値を一定数(具体的には624個)観測することで、
内部状態を完全に復元できてしまいます。
攻撃者が生成された乱数のパターンを読み取ると、
次に生成される「パスワードリセット用トークン」や「一時パスワード」などを
正確に予測できてしまいます。
乱数を生成する際の起点となる「シード値」が
OSのプロセスIDや時刻(ミリ秒単位)などの予測可能な情報から生成されています。
攻撃者はサーバー時刻を外部から推測し、総当たり攻撃(ブルートフォース)によって同じ乱数列を再現できてしまう可能性があります。
セキュリティに強い乱数(CSPRNG)には、「出力から内部状態を推測できない」という厳しい基準を満たしていません。

暗号学的擬似乱数生成器(CSPRNG)
下記の要件があります。
[次値予測不能性]
過去に生成された数値から、次にどんな数字が出るかを数学的に予測することが不可能です。
[状態復元不能性]
もし生成器の内部データが一部漏洩しても、過去の乱数列を逆算して割り出すことができません。

OSが提供する「真の乱数」に近いソースを利用
Linux/macOS: /dev/urandom や getrandom(2) システムコールを利用。
Windows: BCryptGenRandom などの強力なAPIを利用。
CPUの温度変化
キーボードの打鍵タイミング
ネットワークのパケット間隔
といった、外部から予測不可能な「物理的なノイズ」を元にして乱数を生成するため、
攻撃者が同じ値を再現することは極めて困難です。

fisherYatesShuffle
フィッシャー・イェーツのアルゴリズム
そのまま順番に取り出せば「重複なし」のサンプルです。


戻る

著作権情報
ホームページおよプリ等に掲載されている情報等については、いかなる保障もいたしません。
ホームページおよびアプリ等を通じて入手したいかなる情報も複製、販売、出版または使用させたり、
または公開したりすることはできません。
当方は、ホームページおよびアプリ等を利用したいかなる理由によっての障害等が発生しても、
その結果ホームページおよびアプリ等を利用された本人または他の第三者が被った損害について
一切の責任を負わないものとします。