Skip to content

Instantly share code, notes, and snippets.

@timkuijsten
Created October 18, 2017 13:30
Show Gist options
  • Save timkuijsten/f6d2ea7eac78d27cde788e4e7da3e88a to your computer and use it in GitHub Desktop.
Save timkuijsten/f6d2ea7eac78d27cde788e4e7da3e88a to your computer and use it in GitHub Desktop.
<?php
/*
* Copyright (c) 2017 Tim Kuijsten
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*
* Generate a random string of base 56 characters. Either provide a desired
* string length or bit length, not both.
*
* When a bit length is provided, the value is ceiled to the closest factor of
* log2(56). Thus you can get at most 5.8 more bits than requested.
*
* @param int [$strlen] minimum of 1
* @param int [$bitlen] minimum of 1
* @param int [$alphabet] the alphabet must contain at least 2 symbols,
* defaults to base 56 which is optimized for human inspection.
* @return string base 56 string
*/
function random_key($strlen, $bitlen = 0, $alphabet = '23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz')
{
$base = strlen($alphabet); // php strlen runs in constant time
// bits per character log2(56)
$bpc = log($base, 2);
// int in php is unsigned
$maxintbits = (PHP_INT_SIZE / 2) * 8;
if ($strlen && $bitlen) {
return false;
}
if ($strlen) {
/* truncate to ensure string length */
$bitlen = intval($strlen * $bpc);
} else {
$strlen = $bitlen / $bpc;
}
if ($bitlen == 0) {
return false;
}
$result = '';
while ($bitlen > $bpc) {
$fetch = ($bitlen > $maxintbits) ? $maxintbits : $bitlen;
$number = random_int(0, 2 ** $fetch);
if ($number === 0) {
$numbits = 0;
} else {
$numbits = log($number, 2);
}
$chars = 0;
while ($number && (($chars + 1) * $bpc) <= $numbits) {
$remainder = $number % $base;
$number = ($number - $remainder) / $base;
$result .= $alphabet[$remainder];
$chars++;
}
$bitlen -= $chars * $bpc;
}
if ($bitlen > 0) {
$result .= $alphabet[random_int(0, $base - 1)];
}
return $result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment