需求:從 1~10 取出不重複隨機數。本文比較 shuffle、array_unique、array_flip 三種寫法的效能與適用場景,並附贈可自訂字元集、長度、強制含數字字母的密碼產生器。
<?php $arr = range(1, 10); shuffle($arr); // 原地打亂,O(n) print_r($arr); // 直接取前 N 個即為不重複隨機序列 ?>
<?php
$arr = [];
while (count($arr) < 10) {
$arr[] = mt_rand(1, 10);
$arr = array_unique($arr); // 去重,鍵值保留
}
$arr = array_values($arr); // 重建索引
print_r($arr);
?>
<?php
$arr = [];
while (count($arr) < 10) {
$arr[] = mt_rand(1, 10);
$arr = array_flip(array_flip($arr)); // 鍵值互換兩次達到去重並重建索引
}
print_r($arr);
?>
array_flip 去重速度略快於 array_unique,但邏輯較晦澀。# 從 1~1000 抽 100 個不重複數 shuffle: 0.42 秒 array_unique: 1.87 秒 array_flip×2: 1.63 秒
結論: 固定集合抽樣 首選 shuffle();超大範圍少量抽樣才考慮 array_unique 避免建立巨大陣列。
<?php
/**
* 產生符合複雜度要求的隨機密碼
* @param int $length 長度 (預設 16)
* @param string $mode 'ALL' | 'ALNUM' | 'ALPHA' | 'NUM' | 'HEX' | 自訂字元集字串
* @param bool $requireAllClasses 強制包含大小寫、數字、符號 (mode=ALL 時)
* @return string
*/
function generate_password(int $length = 16, string $mode = 'ALL', bool $requireAllClasses = true): string {
$charsets = [
'ALL' => 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()-_=+[]{}|;:,.<>?',
'ALNUM' => 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
'ALPHA' => 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
'NUM' => '0123456789',
'HEX' => '0123456789abcdef',
'SAFE' => 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789', // 移除易混淆字元
];
$charset = $charsets[$mode] ?? $mode; // 允許直接傳入自訂字元集
$charsetLen = strlen($charset);
if ($requireAllClasses && $mode === 'ALL') {
$classes = [
'upper' => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'lower' => 'abcdefghijklmnopqrstuvwxyz',
'digit' => '0123456789',
'special' => '!@#$%^&*()-_=+[]{}|;:,.<>?',
];
// 先各類別取一個,再隨機填滿
$password = '';
foreach ($classes as $classChars) {
$password .= $classChars[random_int(0, strlen($classChars) - 1)];
}
$remaining = $length - count($classes);
} else {
$password = '';
$remaining = $length;
}
for ($i = 0; $i < $remaining; $i++) {
$password .= $charset[random_int(0, $charsetLen - 1)];
}
// 打亂順序
$password = str_shuffle($password);
return $password;
}
// 示範
echo "預設強密碼: " . generate_password() . "\n";
echo "純數字 6 碼: " . generate_password(6, 'NUM') . "\n";
echo "安全字元集 12 碼: " . generate_password(12, 'SAFE') . "\n";
echo "自訂字元集: " . generate_password(10, 'ABC123') . "\n";
?>
random_int() (CSPRNG) 而非 mt_rand() / rand()。str_shuffle() 內部同樣使用 CSPRNG (PHP 7.1+)。time()、microtime()、uniqid() 做種子,可預測。不重複隨機抽樣:固定集合用 shuffle(),超大範圍少量抽樣用 array_unique。密碼/Token 產生務必使用 CSPRNG (random_int/random_bytes) 並支援字元集自訂與複雜度強制。本文提供的 generate_password() 可直接納入專案共用庫。