PHP mt_srand function - php

I've written a code that should generate pseudo-random strings.
I tried to improve the randomness by gathering entropy from user's mouse movements.
Here is my code :
// As described in the PHP documentation
function make_seed() {
list($usec, $sec) = explode(' ', microtime());
return (float) $sec + ((float) $usec * 100000);
}
function rand_string($entropy, $length, $chars) {
mt_srand($entropy . make_seed()); // Here is the important line
$return = '';
$charlen = strlen($chars);
for ($i=0;$i<$length;$i++) {
$rand = mt_rand(0, $charlen) - 1;
$return .= substr($chars, $rand, 1);
}
return $return;
}
$entropy = '18421828841384386426948169412548'; // Mouse movements, changes everytime
echo rand_string($entropy, 20, 'abcdefghijklmnopqrstuvwxz');
I ran the function a couple of times. Some values show up very frequently, so this is a very weak function. I can't understand why. Is there a limit on mt_srand's parameter ? Does it have to be a number ?
Edit : mt_srand() seed must be an INT.

mt_srand() takes an unsigned 32 bit integer to initialize the mersenne twister.
http://svn.php.net/viewvc/php/php-src/trunk/ext/standard/rand.c?revision=321634&view=markup:
194 /* {{{ php_mt_srand
195 */
196 PHPAPI void php_mt_srand(php_uint32 seed TSRMLS_DC)
197 {
198 /* Seed the generator with a simple uint32 */
199 php_mt_initialize(seed, BG(state));
200 php_mt_reload(TSRMLS_C);
201
202 /* Seed only once */
203 BG(mt_rand_is_seeded) = 1;
204 }
205 /* }}} */
I'd suggest searching for means of the underlying system to gather entropy/random bits.
That would be rngd + /dev/random on a *nix machine and CryptGenRandom or (simpler to reach but slower) CAPICOM Utilities.GetRandom() under windows.
Depending on your needs mcrypt_create_iv() can also be a good choice (maybe in combination with something that creates a "readable" string from the iv).

I wrote my own random string generator without using php's rand() function.
function rs($length,$chars)
{
$hex = sha1(microtime()); //contains hexadecimal string
$return = '';
$seedLen = strlen($chars); //length of the source characters string
$posLen = strlen($hex); //length of the hex string
for($i=0;$i<$length;$i++){
$idx_hex = $i % ($posLen-1); //make sure the address is in the hex string (if $i is too big)
$pos = hexdec($hex[$idx_hex].$hex[$idx_hex+1]);
$return .= $chars[$pos % $seedLen];
}
return $return;
}
The way it works is: it generates sha1 hash of current time (a string that looks like 06009da3e0d26f8569b65cb50a774bb6b431a777) then it takes 2 values at a time from the hash and uses that as a hexadecimal "address" of a character in the $chars string.
i.e. in this example if the $chars string is "abcdefghijklmnopqrstuvwxyz" then the first character in the "random" string will be "g" - the letter with index 06 in the chars string.
Limitations:
(1) only first 256 characters will be used from the $chars string (if it's longer than 256 characters)
(2) due to modulo operators, this function is slower than the mt_rand().
edit: mt_rand() uses modulo operators as well, so the speed might be on the same order as this function. i didn't run any comparisons.

Related

PHP How to make generate unique id like Instagram Post [duplicate]

I'm trying to create a randomized string in PHP, and I get absolutely no output with this:
<?php
function RandomString()
{
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$randstring = '';
for ($i = 0; $i < 10; $i++) {
$randstring = $characters[rand(0, strlen($characters))];
}
return $randstring;
}
RandomString();
echo $randstring;
What am I doing wrong?
To answer this question specifically, two problems:
$randstring is not in scope when you echo it.
The characters are not getting concatenated together in the loop.
Here's a code snippet with the corrections:
function generateRandomString($length = 10) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$charactersLength = strlen($characters);
$randomString = '';
for ($i = 0; $i < $length; $i++) {
$randomString .= $characters[random_int(0, $charactersLength - 1)];
}
return $randomString;
}
Output the random string with the call below:
// Echo the random string.
// Optionally, you can give it a desired string length.
echo generateRandomString();
Please note that previous version of this answer used rand() instead of random_int() and therefore generated predictable random strings. So it was changed to be more secure, following advice from this answer.
Note: str_shuffle() internally uses rand(), which is unsuitable for cryptography purposes (e.g. generating random passwords). You want a secure random number generator instead. It also doesn't allow characters to repeat.
One more way.
UPDATED (now this generates any length of string):
function generateRandomString($length = 10) {
return substr(str_shuffle(str_repeat($x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length/strlen($x)) )),1,$length);
}
echo generateRandomString(); // OR: generateRandomString(24)
That's it. :)
There are a lot of answers to this question, but none of them leverage a Cryptographically Secure Pseudo-Random Number Generator (CSPRNG).
The simple, secure, and correct answer is to use RandomLib and don't reinvent the wheel.
For those of you who insist on inventing your own solution, PHP 7.0.0 will provide random_int() for this purpose; if you're still on PHP 5.x, we wrote a PHP 5 polyfill for random_int() so you can use the new API even before you upgrade to PHP 7.
Safely generating random integers in PHP isn't a trivial task. You should always check with your resident StackExchange cryptography experts before you deploy a home-grown algorithm in production.
With a secure integer generator in place, generating a random string with a CSPRNG is a walk in the park.
Creating a Secure, Random String
/**
* Generate a random string, using a cryptographically secure
* pseudorandom number generator (random_int)
*
* This function uses type hints now (PHP 7+ only), but it was originally
* written for PHP 5 as well.
*
* For PHP 7, random_int is a PHP core function
* For PHP 5.x, depends on https://github.com/paragonie/random_compat
*
* #param int $length How many characters do we want?
* #param string $keyspace A string of all possible characters
* to select from
* #return string
*/
function random_str(
int $length = 64,
string $keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
): string {
if ($length < 1) {
throw new \RangeException("Length must be a positive integer");
}
$pieces = [];
$max = mb_strlen($keyspace, '8bit') - 1;
for ($i = 0; $i < $length; ++$i) {
$pieces []= $keyspace[random_int(0, $max)];
}
return implode('', $pieces);
}
Usage:
$a = random_str(32);
$b = random_str(8, 'abcdefghijklmnopqrstuvwxyz');
$c = random_str();
Demo: https://3v4l.org/IMJGF (Ignore the PHP 5 failures; it needs random_compat)
This creates a 20 character long hexadecimal string:
$string = bin2hex(openssl_random_pseudo_bytes(10)); // 20 chars
In PHP 7 (random_bytes()):
$string = base64_encode(random_bytes(10)); // ~14 characters, includes /=+
// or
$string = substr(str_replace(['+', '/', '='], '', base64_encode(random_bytes(32))), 0, 32); // 32 characters, without /=+
// or
$string = bin2hex(random_bytes(10)); // 20 characters, only 0-9a-f
#tasmaniski: your answer worked for me. I had the same problem, and I would suggest it for those who are ever looking for the same answer. Here it is from #tasmaniski:
<?php
$random = substr(md5(mt_rand()), 0, 7);
echo $random;
?>
Here is a youtube video showing us how to create a random number
Depending on your application (I wanted to generate passwords), you could use
$string = base64_encode(openssl_random_pseudo_bytes(30));
Being base64, they may contain = or - as well as the requested characters. You could generate a longer string, then filter and trim it to remove those.
openssl_random_pseudo_bytes seems to be the recommended way way to generate a proper random number in php. Why rand doesn't use /dev/random I don't know.
PHP 7+ Generate cryptographically secure random bytes using random_bytes function.
$bytes = random_bytes(16);
echo bin2hex($bytes);
Possible output
da821217e61e33ed4b2dd96f8439056c
PHP 5.3+ Generate pseudo-random bytes using openssl_random_pseudo_bytes function.
$bytes = openssl_random_pseudo_bytes(16);
echo bin2hex($bytes);
Possible output
e2d1254506fbb6cd842cd640333214ad
The best use case could be
function getRandomBytes($length = 16)
{
if (function_exists('random_bytes')) {
$bytes = random_bytes($length / 2);
} else {
$bytes = openssl_random_pseudo_bytes($length / 2);
}
return bin2hex($bytes);
}
echo getRandomBytes();
Possible output
ba8cc342bdf91143
Here is a simple one-liner that generates a true random string without any script level looping or use of OpenSSL libraries.
echo substr(str_shuffle(str_repeat('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', mt_rand(1,10))), 1, 10);
To break it down so the parameters are clear
// Character List to Pick from
$chrList = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
// Minimum/Maximum times to repeat character List to seed from
$chrRepeatMin = 1; // Minimum times to repeat the seed string
$chrRepeatMax = 10; // Maximum times to repeat the seed string
// Length of Random String returned
$chrRandomLength = 10;
// The ONE LINE random command with the above variables.
echo substr(str_shuffle(str_repeat($chrList, mt_rand($chrRepeatMin,$chrRepeatMax))), 1, $chrRandomLength);
This method works by randomly repeating the character list, then shuffles the combined string, and returns the number of characters specified.
You can further randomize this, by randomizing the length of the returned string, replacing $chrRandomLength with mt_rand(8, 15) (for a random string between 8 and 15 characters).
A better way to implement this function is:
function RandomString($length) {
$keys = array_merge(range(0,9), range('a', 'z'));
$key = "";
for($i=0; $i < $length; $i++) {
$key .= $keys[mt_rand(0, count($keys) - 1)];
}
return $key;
}
echo RandomString(20);
mt_rand is more random according to this and this in PHP 7. The rand function is an alias of mt_rand.
function generateRandomString($length = 15)
{
return substr(sha1(rand()), 0, $length);
}
Tada!
$randstring in the function scope is not the same as the scope where you call it. You have to assign the return value to a variable.
$randstring = RandomString();
echo $randstring;
Or just directly echo the return value:
echo RandomString();
Also, in your function you have a little mistake. Within the for loop, you need to use .= so each character gets appended to the string. By using = you are overwriting it with each new character instead of appending.
$randstring .= $characters[rand(0, strlen($characters))];
First, you define the alphabet you want to use:
$alphanum = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$special = '~!##$%^&*(){}[],./?';
$alphabet = $alphanum . $special;
Then, use openssl_random_pseudo_bytes() to generate proper random data:
$len = 12; // length of password
$random = openssl_random_pseudo_bytes($len);
Finally, you use this random data to create the password. Because each character in $random can be chr(0) until chr(255), the code uses the remainder after division of its ordinal value with $alphabet_length to make sure only characters from the alphabet are picked (note that doing so biases the randomness):
$alphabet_length = strlen($alphabet);
$password = '';
for ($i = 0; $i < $len; ++$i) {
$password .= $alphabet[ord($random[$i]) % $alphabet_length];
}
Alternatively, and generally better, is to use RandomLib and SecurityLib:
use SecurityLib\Strength;
$factory = new RandomLib\Factory;
$generator = $factory->getGenerator(new Strength(Strength::MEDIUM));
$password = $generator->generateString(12, $alphabet);
I've tested performance of most popular functions there, the time which is needed to generate 1'000'000 strings of 32 symbols on my box is:
2.5 $s = substr(str_shuffle(str_repeat($x='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', ceil($length/strlen($x)) )),1,32);
1.9 $s = base64_encode(openssl_random_pseudo_bytes(24));
1.68 $s = bin2hex(openssl_random_pseudo_bytes(16));
0.63 $s = base64_encode(random_bytes(24));
0.62 $s = bin2hex(random_bytes(16));
0.37 $s = substr(md5(rand()), 0, 32);
0.37 $s = substr(md5(mt_rand()), 0, 32);
Please note it is not important how long it really was but which is slower and which one is faster so you can select according to your requirements including cryptography-readiness etc.
substr() around MD5 was added for sake of accuracy if you need string which is shorter than 32 symbols.
For sake of answer: the string was not concatenated but overwritten and result of the function was not stored.
Here's my simple one line solution to generate a use friendly random password, excluding the characters that lookalike such as "1" and "l", "O" and "0", etc... here it is 5 characters but you can easily change it of course:
$user_password = substr(str_shuffle('abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789'),0,5);
One very quick way is to do something like:
substr(md5(rand()),0,10);
This will generate a random string with the length of 10 chars. Of course, some might say it's a bit more heavy on the computation side, but nowadays processors are optimized to run md5 or sha256 algorithm very quickly. And of course, if the rand() function returns the same value, the result will be the same, having a 1 / 32767 chance of being the same. If security's the issue, then just change rand() to mt_rand()
function gen_uid($l=5){
return substr(str_shuffle("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"), 10, $l);
}
echo gen_uid();
Default Value[5]: WvPJz
echo gen_uid(30);
Value[30]: cAiGgtf1lDpFWoVwjykNKXxv6SC4Q2
Short Methods..
Here are some shortest method to generate the random string
<?php
echo $my_rand_strng = substr(str_shuffle("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), -15);
echo substr(md5(rand()), 0, 7);
echo str_shuffle(MD5(microtime()));
?>
Helper function from Laravel 5 framework
/**
* Generate a "random" alpha-numeric string.
*
* Should not be considered sufficient for cryptography, etc.
*
* #param int $length
* #return string
*/
function str_random($length = 16)
{
$pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
return substr(str_shuffle(str_repeat($pool, $length)), 0, $length);
}
Since php7, there is the random_bytes functions.
https://www.php.net/manual/ru/function.random-bytes.php
So you can generate a random string like that
<?php
$bytes = random_bytes(5);
var_dump(bin2hex($bytes));
?>
from the yii2 framework
/**
* Generates a random string of specified length.
* The string generated matches [A-Za-z0-9_-]+ and is transparent to URL-encoding.
*
* #param int $length the length of the key in characters
* #return string the generated random key
*/
function generateRandomString($length = 10) {
$bytes = random_bytes($length);
return substr(strtr(base64_encode($bytes), '+/', '-_'), 0, $length);
}
function rndStr($len = 64) {
$randomData = file_get_contents('/dev/urandom', false, null, 0, $len) . uniqid(mt_rand(), true);
$str = substr(str_replace(array('/','=','+'),'', base64_encode($randomData)),0,$len);
return $str;
}
This one was taken from adminer sources:
/** Get a random string
* #return string 32 hexadecimal characters
*/
function rand_string() {
return md5(uniqid(mt_rand(), true));
}
Adminer, database management tool written in PHP.
/**
* #param int $length
* #param string $abc
* #return string
*/
function generateRandomString($length = 10, $abc = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
{
return substr(str_shuffle($abc), 0, $length);
}
Source from http://www.xeweb.net/2011/02/11/generate-a-random-string-a-z-0-9-in-php/
Another one-liner, which generates a random string of 10 characters with letters and numbers. It will create an array with range (adjust the second parameter to set the size), loops over this array and assigns a random ASCII character (range 0-9 or a-z), then implodes the array to get a string.
$str = implode('', array_map(function () { return chr(rand(0, 1) ? rand(48, 57) : rand(97, 122)); }, range(0, 9)));
Note: this only works in PHP 5.3 and later
One liner.
It is fast for huge strings with some uniqueness.
function random_string($length){
return substr(str_repeat(md5(rand()), ceil($length/32)), 0, $length);
}
function randomString($length = 5) {
return substr(str_shuffle(implode(array_merge(range('A','Z'), range('a','z'), range(0,9)))), 0, $length);
}
Here is how I am doing it to get a true unique random key:
$Length = 10;
$RandomString = substr(str_shuffle(md5(time())), 0, $Length);
echo $RandomString;
You can use time() since it is a Unix timestamp and is always unique compared to other random mentioned above. You can then generate the md5sum of that and take the desired length you need from the generated MD5 string. In this case I am using 10 characters, and I could use a longer string if I would want to make it more unique.
I hope this helps.
The edited version of the function works fine, but there is just one issue I found: You used the wrong character to enclose $characters, so the ’ character is sometimes part of the random string that is generated.
To fix this, change:
$characters = ’0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ’;
to:
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
This way only the enclosed characters are used, and the ’ character will never be a part of the random string that is generated.
function generateRandomString($length = 10, $hasNumber = true, $hasLowercase = true, $hasUppercase = true): string
{
$string = '';
if ($hasNumber)
$string .= '0123456789';
if ($hasLowercase)
$string .= 'abcdefghijklmnopqrstuvwxyz';
if ($hasUppercase)
$string .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
return substr(str_shuffle(str_repeat($x = $string, ceil($length / strlen($x)))), 1, $length);
}
and use:
echo generateRandomString(32);
I liked the last comment which used openssl_random_pseudo_bytes, but it wasn't a solution for me as I still had to remove the characters I didn't want, and I wasn't able to get a set length string. Here is my solution...
function rndStr($len = 20) {
$rnd='';
for($i=0;$i<$len;$i++) {
do {
$byte = openssl_random_pseudo_bytes(1);
$asc = chr(base_convert(substr(bin2hex($byte),0,2),16,10));
} while(!ctype_alnum($asc));
$rnd .= $asc;
}
return $rnd;
}

Convert string to consistent but random 1 of 10 options

I have many strings. Each string something like:
"i_love_pizza_123"
"whatever_this_is_now_later"
"programming_is_awesome"
"stack_overflow_ftw"
...etc
I need to be able to convert each string to a random number, 1-10. Each time that string gets converted, it should consistently be the same number. A sampling of strings, even with similar text should result in a fairly even spread of values 1-10.
My first thought was to do something like md5($string), then break down a-f,0-9 into ten roughly-equal groups, determine where the first character of the hash falls, and put it in that group. But doing so seems to have issues when converting 16 down to 10 by multiplying by 0.625, but that causes the spread to be uneven.
Thoughts on a good method to consistently convert a string to a random/repeatable number, 1-10? There has to be an easier way.
Here's a quick demo how you can do it.
function getOneToTenHash($str) {
$hash = hash('sha256', $str, true);
$unpacked = unpack("L", $hash); // convert first 4 bytes of hash to 32-bit unsigned int
$val = $unpacked[1];
return ($val % 10) + 1; // get 1 - 10 value
}
for ($i = 0; $i < 100; $i++) {
echo getOneToTenHash('str' . $i) . "\n";
}
How it works:
Basically you get the output of a hash function and downscale it to desired range (1..10 in this case).
In the example above, I used sha256 hash function which returns 32 bytes of arbitrary binary data. Then I extract just first 4 bytes as integer value (unpack()).
At this point I have a 4 bytes integer value (0..4294967295 range). In order to downscale it to 1..10 range I just take the remainder of division by 10 (0..9) and add 1.
It's not the only way to downscale the range but an easy one.
So, the above example consists of 3 steps:
get the hash value
convert the hash value to integer
downscale integer range
A much shorter example with crc32() function which returns integer value right away thus allowing us to omit step 2:
function getOneToTenHash($str) {
$int = crc32($str); // 0..4294967295
return ($int % 10) + 1; // 1..10
}
below maybe what u want
$inStr = "hello world";
$md5Str = md5($inStr);
$len = strlen($md5Str);
$out = 0;
for($i=0; $i<$len; $i++) {
$out = 7*$out + intval($md5Str[$i]); // if you want more random, can and random() here
}
$out = ($out % 10 + 9)%10; // scope= [1,10]

php How to make a proper hash function that will handle given strings

I want to create a hash function that will receive strings and output the corresponding value in an array that has predefined "proportions". For instance, if my array holds the values:
[0] => "output number 1"
[1] => "output number 2"
[2] => "output number 3"
Then the hash function int H(string) should return only values in the range 0 and 2 for any given string (an input string will always return the same key).
The thing is that i want it to also make judgement by predefined proportions so, for instance
85% of given strings will hash out as 0, 10% as 1 and 5% as 2. If there are functions that can emulate normal distribution that will be even better.
I also want it to be fast as it will run frequently. Can someone point me to the right direction on how to approach this in php? I believe I'm not the first one that asked this but I came short digging on SO for an hour.
EDIT:
What i did until now is built a hash function in c. It does the above hashing without proportions (still not comfortable with php):
int StringFcn (const void *key, size_t arrSize)
{
char *str = key;
int totalAsciiVal = 0;
while(*str)
{
totalAsciiVal += *str++;
}
return totalAsciiVal % arrSize;
}
What about doing something like this:
// Hash the string so you can pretty much guarantee it will have a number in it and it is relatively "random"
$hash = sha1($string);
// Iterate through string and get ASCII values
$chars = str_split($hash);
$num = 0;
foreach ($chars as $char) {
$num += ord($int);
}
// Get compare modulo 100 of the number
if ($num % 100 < 85) {
return 0;
}
if ($num % 100 < 95) {
return 1;
}
return 2;
Edit:
Instead of hashing with sha1, you can get a sufficiently large integer directly using crc32 (thanks to #nivrig in the comments).
// Convert string to integer
$num = crc32($string);
// Get compare modulo 100 of the number
if ($num % 100 < 85) {
return 0;
}
if ($num % 100 < 95) {
return 1;
}
return 2;

How to generate random key separated by hypen

I am working on Yii. I want to generate 20 digit random keys. I had written a function as -
public function GenerateKey()
{
//for generating random confirm key
$length = 20;
$chars = array_merge(range(0,9), range('a','z'), range('A','Z'));
shuffle($chars);
$password = implode(array_slice($chars, 0, $length));
return $password;
}
This function is generating 20 digit key correctly. But I want the key in a format like
"g12a-Gh45-gjk7-nbj8-lhk8". i.e. separated by hypen. So what changes do I need to do?
You can use chunk_split() to add the hyphens. substr() is used to remove the trailing hyphen it adds, leaving only those hyphens that actually separate groups.
return substr(chunk_split($password, 4, '-'), 0, 24);
However, note that shuffle() not only uses a relatively poor PRNG but also will not allow the same character to be used twice. Instead, use mt_rand() in a for loop, and then using chunk_split() is easy to avoid:
$password = '';
for ($i = 0; $i < $length; $i++) {
if ( $i != 0 && $i % 4 == 0 ) { // nonzero and divisible by 4
$password .= '-';
}
$password .= $chars[mt_rand(0, count($chars) - 1)];
}
return $password;
(Even mt_rand() is not a cryptographically secure PRNG. If you need to generate something that must be extremely hard to predict (e.g. an encryption key or password reset token), use openssl_random_pseudo_bytes() to generate bytes and then a separate function such as bin2hex() to encode them into printable characters. I am not familiar with Yii, so I cannot say whether or not it has a function for this.)
You can use this Yii internal function:
Yii::app()->getSecurityManager()->generateRandomString($length);

PHP function to create 8 chars long hash ([a-z] = no numbers allowed)

I need PHP function that will create 8 chars long [a-z] hash from any input string.
So e.g. when I'll submit "Stack Overflow" it will return e.g. "gdqreaxc" (8 chars [a-z] no numbers allowed)
Perhaps something like:
$hash = substr(strtolower(preg_replace('/[0-9_\/]+/','',base64_encode(sha1($input)))),0,8);
This produces a SHA1 hash, base-64 encodes it (giving us the full alphabet), removes non-alpha chars, lowercases it, and truncates it.
For $input = 'yar!';:
mwinzewn
For $input = 'yar!!';:
yzzhzwjj
So the spread seems pretty good.
This function will generate a hash containing evenly distributed characters [a-z]:
function my_hash($string, $length = 8) {
// Convert to a string which may contain only characters [0-9a-p]
$hash = base_convert(md5($string), 16, 26);
// Get part of the string
$hash = substr($hash, -$length);
// In rare cases it will be too short, add zeroes
$hash = str_pad($hash, $length, '0', STR_PAD_LEFT);
// Convert character set from [0-9a-p] to [a-z]
$hash = strtr($hash, '0123456789', 'qrstuvwxyz');
return $hash;
}
By the way, if this is important for you, for 100,000 different strings you'll have ~2% chance of hash collision (for a 8 chars long hash), and for a million of strings this chance rises up to ~90%, if my math is correct.
function md5toabc($myMD5)
{
$newString = "";
for ($i = 0; $i < 16; $i+=2)
{
//add the first val of 0-15 to the second val of 0-15 for a range of 0-30
$myintval = hexdec(substr($myMD5, $i, $i +1) ) +
hexdec(substr($myMD5, $i+1, $i +2) );
// mod by 26 and add 97 to get to the lowercase ascii range
$newString .= chr(($myintval%26) + 97);
}
return $newString;
}
Note this introduces bias to various characters, but do with it what you will.
(Like when you roll two dice, the most common value is a 7 combined...) plus the modulo, etc...
one can give you a good a-p{8} (but not a-z) by using and modifying (the output of) a well known algo:
function mini_hash( $string )
{
$h = hash( 'crc32' , $string );
for($i=0;$i<8;$i++) {
$h{$i} = chr(96+hexdec($h{$i}));
}
return $h;
}
interesting set of constraints you posted there
how about
substr (preg_replace(md5($mystring), "/[1-9]/", ""), 0, 8 );
you could add a bit more entorpy by doing a
preg_replace($myString, "1", "g");
preg_replace($myString, "2", "h");
preg_replace($myString, "3", "i");
etc instead of stripping the digits.

Categories