這工作,與PHP 7.0 random_bytes()函數:
<?php
function random_key($length, $safe = false) {
if ($safe !== false) {
$bad_words = array_map('trim', file('/path/to/bad-words.txt', FILE_IGNORE_NEW_LINES));
} else {
$bad_words = NULL;
}
$j = 0;
do {
$bytes = (ceil($length/4) * 3); // Must be divisible by 3, otherwise base64 encoding introduces padding characters, and the last character biases towards "0 4 8 A E I M Q U Y c g k o s w".
$bytes = ($bytes * 2); // Get even more, because some characters will be dropped.
$key = random_bytes($bytes);
$key = base64_encode($key);
$key = str_replace(array('0', 'O', 'I', 'l', '/', '+'), '', $key); // Make URL safe (base58), and drop similar looking characters (no substitutions, as we don't want to bias certain characters)
$key = substr($key, 0, $length);
if (preg_match('/[^a-zA-Z0-9]/', $key)) {
exit_with_error('Invalid characters detected in key "' . $key . '"');
}
$valid = (strlen($key) == $length);
if ($bad_words) {
foreach ($bad_words as $bad_word) {
if (stripos($key, $bad_word) !== false) {
$valid = false;
break;
}
}
}
if ($valid) {
return $key;
}
} while ($j++ < 10);
exit_with_error('Cannot generate a safe key after 10 attempts.');
}
?>
這段代碼顯示了base64_encode()
功能如何偏置到某些字符:
<?php
$characters = [];
for ($k = 0; $k < 500000; $k++) {
$key = base64_encode(random_bytes(32)); // 32 bytes results in "=" padding; try changing to 30 to fix.
foreach (str_split($key) as $c) {
if (!isset($characters[$c])) {
$characters[$c] = 0;
}
$characters[$c]++;
}
}
$characters = array_filter($characters, function($value) {
return ($value > 343750); // ((((33/3)*4)*500000)/64) = 343750, everything else is about ~327000
});
ksort($characters, SORT_STRING);
print_r($characters);
?>
如果你不喜歡「+ 「和」/「,你可以用」 - 「和」_「來代替它們 - 這就是Base64的另一種風格,叫做」base64url「。有關更多信息,請參見[Wikipedia](http://en.wikipedia.org/wiki/Base64)。 –
@ Anton-Samsonov,好點,儘管我仍然可以放下下劃線字符(或者使用句號),因爲我有幾個用戶將其視爲空間的實例(推測鏈接也使用了下劃線隱藏該字符的字體樣式)...但原則上,熵是190(ish)比特是否正確? (不是真的很重要,更重要的是檢查數學部分)。 –