How to decrease runtime for generating permutations of a string? - php

I have written a function that takes in a MD5 hashvalue and finds its input/original value by permuting all possible combinations of a string. As per BIT_CHEETAH's answer on a SO question:
... you cannot decrypt MD5 without attempting something like brute force hacking which is extremely resource intensive, not practical, and unethical.
(Source: encrypt and decrypt md5)
I'm well aware of this, however, I am using this scenario to implement a string permutation function. I would also like to stick to the recursive methodology as opposed to others. The best summary of doing this is probably summarised by Mark Byers post:
- Try each of the letters in turn as the first letter and then find all
the permutations of the remaining letters using a recursive call.
- The base case is when the input is an empty string the only permutation is the empty string.
(Generating all permutations of a given string)
Anyway, so I implemented this and got the following:
function matchMD5($possibleChars, $md5, $concat, $length) {
for($i = 0; $i < strlen($possibleChars); $i++) {
$ch = $possibleChars[$i];
$concatSubstr = $concat.$ch;
if(strlen($concatSubstr) != $length) {
matchMD5($possibleChars, $md5, $concatSubstr, $length);
}
else if(strlen($concatSubstr) == $length) {
$tryHash = hash('md5', $concatSubstr);
if ($tryHash == $md5) {
echo "Match! $concatSubstr ";
return $concatSubstr;
}
}
}
}
Works 100%, however when I pass in a four character array, my server runs 10.7 seconds to generate a match where the match lies approximately 1/10th of the way of all possible permutations. My valid characters in which the functions permutes, called, $possibleChars, contains all alphanumeric characters plus a few selected punctionations:
0123456789.,;:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
Question: Can the above code be written to run faster somehow?

When doing brute-force, you have to run through all the possibilities, there is not way of cutting a corner there. So you are left with profiling your code to find out what the application spends the most time doing and then trying to optimize that.

Related

PHP Random string generation miraculously generated the same string

So I've got a fairly simple function in PHP that renders 10 character long order IDs:
function createReference($length = 10)
{
$characters = 'ABCDEFGHIJKLMNPQRSTUVWXYZ123456789';
$string = '';
for ($i = 0; $i < $length; $i++) {
$string .= $characters[rand(0, strlen($characters) - 1)];
}
return $string;
}
However, today on the 154020th table record, it generated the same 10-character ID as a previous order ID (which was the 144258th record in the table), and tried to insert it. Since I have a UNIQUE restriction on the column, I got an error and I received a notification from this.
According to my calculations, the script above creates 34^10 = 2.064.377.754.059.776 different possibilities.
I've read some stuff about rand() and mt_rand() doing different stuff but that shouldnt be an issue on PHP 7.1+. The script is running on PHP 7.3.
So should I buy a lottery ticket right now, or is there something predictable about the pseudo-randomness being used here? If so, what is a solution to have better distribution?
Assuming rand() is a true RNG, then the expected chance to generate a duplicate reaches 50% after reaching a little more than the square root of all possibilities (see "Birthday problem" for a more precise statement and formulas). The square root of 34^10 is 45435424, so it's well over 144258, but of course, rand() is far from being a perfect or "true" RNG.
In any case, generating a unique random identifier using rand or mt_rand (rather than a cryptographic RNG such as random_int) is a bad idea anyway. Depending on whether or not IDs have to be hard to guess, or whether or not the ID alone is enough to grant access to the resource, it may or may not be a better idea to use auto-incrementing record numbers rather than random numbers. See my section "Unique Random Identifiers" for further considerations.
See also this question.

PHP built in functions complexity (isAnagramOfPalindrome function)

I've been googling for the past 2 hours, and I cannot find a list of php built in functions time and space complexity. I have the isAnagramOfPalindrome problem to solve with the following maximum allowed complexity:
expected worst-case time complexity is O(N)
expected worst-case space complexity is O(1) (not counting the storage required for input arguments).
where N is the input string length. Here is my simplest solution, but I don't know if it is within the complexity limits.
class Solution {
// Function to determine if the input string can make a palindrome by rearranging it
static public function isAnagramOfPalindrome($S) {
// here I am counting how many characters have odd number of occurrences
$odds = count(array_filter(count_chars($S, 1), function($var) {
return($var & 1);
}));
// If the string length is odd, then a palindrome would have 1 character with odd number occurrences
// If the string length is even, all characters should have even number of occurrences
return (int)($odds == (strlen($S) & 1));
}
}
echo Solution :: isAnagramOfPalindrome($_POST['input']);
Anyone have an idea where to find this kind of information?
EDIT
I found out that array_filter has O(N) complexity, and count has O(1) complexity. Now I need to find info on count_chars, but a full list would be very convenient for future porblems.
EDIT 2
After some research on space and time complexity in general, I found out that this code has O(N) time complexity and O(1) space complexity because:
The count_chars will loop N times (full length of the input string, giving it a start complexity of O(N) ). This is generating an array with limited maximum number of fields (26 precisely, the number of different characters), and then it is applying a filter on this array, which means the filter will loop 26 times at most. When pushing the input length towards infinity, this loop is insignificant and it is seen as a constant. Count also applies to this generated constant array, and besides, it is insignificant because the count function complexity is O(1). Hence, the time complexity of the algorithm is O(N).
It goes the same with space complexity. When calculating space complexity, we do not count the input, only the objects generated in the process. These objects are the 26-elements array and the count variable, and both are treated as constants because their size cannot increase over this point, not matter how big the input is. So we can say that the algorithm has a space complexity of O(1).
Anyway, that list would be still valuable so we do not have to look inside the php source code. :)
A probable reason for not including this information is that is is likely to change per release, as improvements are made / optimizations for a general case.
PHP is built on C, Some of the functions are simply wrappers around the c counterparts, for example hypot a google search, a look at man hypot, in the docs for he math lib
http://www.gnu.org/software/libc/manual/html_node/Exponents-and-Logarithms.html#Exponents-and-Logarithms
The source actually provides no better info
https://github.com/lattera/glibc/blob/a2f34833b1042d5d8eeb263b4cf4caaea138c4ad/math/w_hypot.c (Not official, Just easy to link to)
Not to mention, This is only glibc, Windows will have a different implementation. So there MAY even be a different big O per OS that PHP is compiled on
Another reason could be because it would confuse most developers.
Most developers I know would simply choose a function with the "best" big O
a maximum doesnt always mean its slower
http://www.sorting-algorithms.com/
Has a good visual prop of whats happening with some functions, ie bubble sort is a "slow" sort, Yet its one of the fastest for nearly sorted data.
Quick sort is what many will use, which is actually very slow for nearly sorted data.
Big O is worst case - PHP may decide between a release that they should optimize for a certain condition and that will change the big O of the function and theres no easy way to document that.
There is a partial list here (which I guess you have seen)
List of Big-O for PHP functions
Which does list some of the more common PHP functions.
For this particular example....
Its fairly easy to solve without using the built in functions.
Example code
function isPalAnagram($string) {
$string = str_replace(" ", "", $string);
$len = strlen($string);
$oddCount = $len & 1;
$string = str_split($string);
while ($len > 0 && $oddCount >= 0) {
$current = reset($string);
$replace_count = 0;
foreach($string as $key => &$char) {
if ($char === $current){
unset($string[$key]);
$len--;
$replace_count++;
continue;
}
}
$oddCount -= ($replace_count & 1);
}
return ($len - $oddCount) === 0;
}
Using the fact that there can not be more than 1 odd count, you can return early from the array.
I think mine is also O(N) time because its worst case is O(N) as far as I can tell.
Test
$a = microtime(true);
for($i=1; $i<100000; $i++) {
testMethod("the quick brown fox jumped over the lazy dog");
testMethod("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
testMethod("testest");
}
printf("Took %s seconds, %s memory", microtime(true) - $a, memory_get_peak_usage(true));
Tests run using really old hardware
My way
Took 64.125452041626 seconds, 262144 memory
Your way
Took 112.96145009995 seconds, 262144 memory
I'm fairly sure that my way is not the quickest way either.
I actually cant see much info either for languages other than PHP (Java for example).
I know a lot of this post is speculating about why its not there and theres not a lot drawing from credible sources, I hope its an partially explained why big O isnt listed in the documentation page though

How to generate unique secure random string in PHP?

I want to add random string as token for form submission which is generated unique forever. I have spent to much time with Google but I am confused which combination to use?
I found so many ways to do this when I googled:
1) Combination of character and number.
2) Combination of character, number and special character.
3) Combination of character, number, special character and date time.
Which combination may i use?
How many character of random string may I generate.?
Any other method which is secure then please let me know.?
Here are some considerations:
Alphabet
The number of characters can be considered the alphabet for the encoding. It doesn't affect the string strength by itself but a larger alphabet (numbers, non-alpha-number characters, etc.) does allow for shorter strings of similar strength (aka keyspace) so it's useful if you are looking for shorter strings.
Input Values
To guarantee your string to be unique, you need to add something which is guaranteed to be unique.
Random value is a good seed value if you have a good random number generator
Time is a good seed value to add but it may not be unique in a high traffic environment
User ID is a good seed value if you assume a user isn't going to create sessions at the exact same time
Unique ID is something the system guarantees is unique. This is often something that the server will guarantee / verify is unique, either in a single server deployment or distributed deployment. A simple way to do this is to add a machine ID and machine unique ID. A more complicated way to do this is to assign key ranges to machines and have each machine manage their key range.
Systems that I've worked with that require absolute uniqueness have added a server unique id which guarantees a item is unique. This means the same item on different servers would be seen as different, which was what was wanted here.
Approach
Pick one more input values that matches your requirement for uniqueness. If you need absolute uniqueness forever, you need something that you control that you are sure is unique, e.g. a machine associated number (that won't conflict with others in a distributed system). If you don't need absolute uniqueness, you can use a random number with other value such as time. If you need randomness, add a random number.
Use an alphabet / encoding that matches your use case. For machine ids, encodings like hexadecimal and base 64 are popular. For machine-readable ids, for case-insensitive encodings, I prefer base32 (Crockford) or base36 and for case-sensitive encodings, I prefer base58 or base62. This is because these base32, 36, 58 and 62 produce shorter strings and (vs. base64) are safe across multiple uses (e.g. URLs, XML, file names, etc.) and don't require transformation between different use cases.
You can definitely get a lot fancier depending on your needs, but I'll just throw this out there since it's what I use frequently for stuff like what you are describing:
md5(rand());
It's quick, simple and easy to remember. And since it's hexadecimal it plays nicely with others.
Refer to this SO Protected Question. This might be what you are looking.
I think its better to redirect you to a previously asked question which has more substantive answers.You will find a lot of options.
Try the code, for function getUniqueToken() which returns you unique string of length 10 (default).
/*
This function will return unique token string...
*/
function getUniqueToken($tokenLength = 10){
$token = "";
//Combination of character, number and special character...
$combinationString = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789*#&$^";
for($i=0;$i<$tokenLength;$i++){
$token .= $combinationString[uniqueSecureHelper(0,strlen($combinationString))];
}
return $token;
}
/*
This helper function will return unique and secure string...
*/
function uniqueSecureHelper($minVal, $maxVal) {
$range = $maxVal - $minVal;
if ($range < 0) return $minVal; // not so random...
$log = log($range, 2);
$bytes = (int) ($log / 8) + 1; // length in bytes
$bits = (int) $log + 1; // length in bits
$filter = (int) (1 << $bits) - 1; // set all lower bits to 1
do {
$rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
$rnd = $rnd & $filter; // discard irrelevant bits
} while ($rnd >= $range);
return $minVal + $rnd;
}
Use this code (two function), you can increase string length by passing int parameter like getUniqueToken(15).
I use your 2nd idea (Combination of character, number and special character), which you refine after googling. I hope my example will help you.
You should go for 3 option. Because it has date and time so it become every time unique.
And for method have you tried
str_shuffle($string)
Every time it generates random string from $string.
End then use substr
($string , start , end)
to cut it down.
End if you want date and time then concatenate the result string with it.
An easily understandable and effective code to generate random strings in PHP. I do not consider predictability concerns important in this connection.
<?php
$d = str_shuffle('0123456789');
$C = str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ');
$m = str_shuffle('abcdefghijklmnopqrstuvwxyz');
$s = str_shuffle('#!$&()*+-_~');
$l=9; //min 4
$r=substr(str_shuffle($d.$C.$m.$s),0,$l);echo $r.'<br>';
$safe=substr($d,0,1).substr($C,0,1).substr($m,0,1).mb_substr($s,0,1);
$r=str_shuffle($safe.substr($r,0,$l-4));//always at least one digit, special, small and capital
// this also allows for 0,1 or 2 of each available characters in string
echo $r;
exit;
?>
For unique string use uniqid().
And to make it secure, use hashing algorithms
for example :
echo md5(uniqid())

Never Generate Random Number Again

I am looking for a random number generating PHP Solution which did not generate same number again.. is there any solution then please let me know..
I need this solution for one of my Project which generate uniqu key for URL and i don't want to check Generated number is existed or not from the data..
Thanks..
--------- EDIT ----------
I am using this random number generating method is its help full?
function randomString($length = 10, $chars = '1234567890') {
// Alpha lowercase
if ($chars == 'alphalower') {
$chars = 'abcdefghijklmnopqrstuvwxyz';
}
// Numeric
if ($chars == 'numeric') {
$chars = '1234567890';
}
// Alpha Numeric
if ($chars == 'alphanumeric') {
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
}
// Hex
if ($chars == 'hex') {
$chars = 'ABCDEF1234567890';
}
$charLength = strlen($chars)-1;
for($i = 0 ; $i < $length ; $i++)
{
$randomString .= $chars[mt_rand(0,$charLength)];
}
return $randomString;
}
Look at the php function uniqid():
http://php.net/manual/en/function.uniqid.php
It's impossible to generate a random number which is unique - if the generator is dependent on state, then the output is by definition not random.
It is possible to generate a set of random numbers and remove duplicates (although at the numbers again cease to be be truly random).
Do you really need a random number or do you need a sequence number or a unique identifier - these are 3 separate things.
which generate unique key for URL
MySQL and SQLite both support auto-increment column types which will be unique (effectively the same as a sequence number). MySQL even has a mechanism for ensuring uniqueness across equivalent nodes - even where they are not tightly coupled. Oracle provides sequence generators.
Both MySQL and PHP have built-in functionality for generating uuids, although since most DBMS support surrogate key generation, there is little obvious benefit to this approach.
You can use a database... Everytime a random number has shown up, put it in a database and next time, compare the random number of the new script with those already in the database.
Use a random number generator, keep stored the already generated values, discard and generate again when you get a duplicate number.
Ignore uniqids and stuff like that because they are just plain wrong.
There are no real "perfect and low price" random number generators!!
The best that can be done from mathematical functions are pseudorandom which in the end seem random enough for most intents and purposes.
mt_rand function uses the Mersenne twister, which is a pretty good PRNG!
so it's probably going to be good enough for most casual use.
give a look here for more info: http://php.net/manual/en/function.mt-rand.php
a possible code implementation is
<?php
$random = mt_rand($yourMin, $yourMax);
?>
EDITD:
find a very good explanation here:
Generate cryptographically secure random numbers in php
The typical answer is to use a GUID or UUID, although I avoid those forms that use only random numbers. (Eg, avoid version 4 GUID or UUIDs)

generate a 5 char long string 0-9 a-z

I need a function in php that can generate a 5 char long string with numbers and a-z
What should I look into?
Other's have already provided you with correct answers, but here's a one-liner, just for the sake of it:
$code = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyz'), 0, 5);
str_shuffle randomizes the above string, then substr takes the first 5 letters of that shuffled string. Simple.
As noted in comments for this answer, this function only generates strings that have only unique characters. If one would like to have the strings where even "aaaaa" is possible, here's a little function that allows just that:
function generate($len) {
return substr(str_shuffle(str_repeat('0123456789abcdefghijklmnopqrstuvwxyz', $len)), 0, $len);
}
echo generate(5);
str_repeat repeats the 0-9a-z string $len times, so every letter has an almost equal possibility for every position. (Read the comments on why only "almost")
For kicks, here's an alternate approach:
//create a random base 36 string
$str = base_convert(rand(), 10, 36);
substr and concatenate as necessary to satisfy length requirements.
This will not give unique characters (e.g., 'aa11a' would be a possible output) -- which may or may not be what the OP wants. Also, the fact that you may need to run the function multiple times to get a string of the requested length means performance may not be spectacular, but if you're only calling this function once or twice, it won't matter.
Here's a more complete implementation:
function randstr($len) {
$currLen = 0;
$value = '';
while($currLen < $len) {
$new = base_convert(rand(), 10, 36);
$value .= $new;
$currLen += strlen($new);
}
//$value may be longer than the requested $len
return substr($value, 0, $len);
}
It's also worth noting that this string will be of less-than-perfect randomness -- the first char of each string output by base_convert will have a bias toward the lower end of the spectrum (as rand() will not completely fill a whole char's worth of bits every time). Ideally, you want a number of bits out of rand that will exactly fill some number of base-36 chars.
Using a source of entropy that gives you more bits than you need for the string in the first place (like /dev/urandom) would resolve this issue. But for most applications, the loss of entropy won't matter enough to justify the overhead of reading /dev/urandom.
Alternately, you could simply throw away the first char of each base_convert() call.
Here’s some example generator:
$length = 5;
$charset = '0123456789abcdefghijklmnopqrstuvwxyz';
$str = '';
while ($length--) {
$str .= $charset[rand() % count($charset)];
}
Do you mean a random string?
If so, simply create a string containing the 36 characters, generate 5 random numbers and create the string based on the character positions (pseudo-code):
string src = "0123456789abcdefghijklmnopqrstuvwxyz"
string dst = ""
for i = 1 to 5:
dst = dst + src[random(len(src))]
If you want 5 unique characters, you do the same thing but with one slight difference.
Generate the first random number in the range 0 through 35, the second in the range 0 through 34 and so on.
Then, as you add the character from the source string to your own string, replace the used character in the source string with the last character in the source string. This will prevent the same character from being selected twice:
string src = "0123456789abcdefghijklmnopqrstuvwxyz"
int srclen = len(src)
string dst = ""
for i = 1 to 5:
idx = randon(len(src))
dst = dst + src[idx]
src[idx] = src[srclen-1]
srclen = srclen - 1
Aside: #Tatu has provided a simple solution using str_shuffle which is a more elegant way of doing that last method (unique characters) but I'm not convinced it's the most efficient way since it's likely to involve a lot of swaps to get a decent shuffle. The method here seems to me to be more likely to be faster.
Keep that in mind if performance is important, but also keep in mind that I haven't tested how good it is - it may be fast enough - it may even blow my solution out of the water :-) As with all performance-related things, measure, don't guess.
http://php.net/manual/en/function.chr.php, in case you dislike hardcoding the alphabet.
Yet another approach, for funsies. Could be shortened - here it's a bit verbose, for readability.
function rand_string($length=5) {
$values = str_split("abcdefghijklmnopqrstuvwxyz0123456789"));
shuffle($values);
$values = array_flip($values);
$string = implode(array_rand($lenght));
return $string;
}

Categories