calande Posted September 30, 2008 Share Posted September 30, 2008 Hello, I am learning, and I have no specific need for this at the moment, so it's just for fun. How can I generate a series of short strings composed only of lowercase letters, uppercase letters, and numbers so that all strings are different? Think about those TinyURL URLs that are short and uniquely identify URL shortcuts. How could we get started? Could we create a large array containing all uppercase and lowercase letters + numbers from 0 to 9? How could we do it easily (not manually)? With a loop? How? Then, how do we have PHP count from a to z, to A to Z, to 0 to 9, and always increment one unit? One other thing to consider is, suppose we pick this value from the latest record in a database: H7fs, how could we ask PHP to tell us what value the next record should have? (in this case, the next record should have H7ft). This boggles the mind, doesn't it? How would you do? Thanks! Quote Link to comment Share on other sites More sharing options...
trq Posted September 30, 2008 Share Posted September 30, 2008 If your just looking for some random string you could easily create a function to do so. <?php function randstring($length=10) { $array = array_merge(range('a','z'),range('A','Z'),range(0,9)); for ($i = 0; $i <= $length; $i++) { $str .= $array[rand(0,61)]; } return $str; } ?> Not tested. Quote Link to comment Share on other sites More sharing options...
php.ajax.coder Posted September 30, 2008 Share Posted September 30, 2008 Try this Script <?PHP $chars = array("A","B","C","D","E","F","G","H","I","J","K","L","M","N", "O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b", "c","d","e","f","g","h","i","j","k","l","m","n","o","p", "q","r","s","t","u","v","w","x","y","z", "1","2","3","4","5","6","7","8","9","0"); //Lenght of String $string_length = 6; //Result String $result = ""; //Array Length $count = count($strs) - 1; for ($i = 0; $i <= $string_length; $i++){ $rand = rand(0, $count); $result = $result . $strs[$rand]; } echo $result; ?> Quote Link to comment Share on other sites More sharing options...
calande Posted September 30, 2008 Author Share Posted September 30, 2008 Thanks guys, the thing is that it should start with just one character and count on and on like this: 1, 2, 3, ..., a, b, c, ..., A, B, C, ..., 1a, 1b, 1c, ..., 1A, 1B, 1C,..., etc... Instead of just generating a random 5-chars string. Any idea? Quote Link to comment Share on other sites More sharing options...
discomatt Posted September 30, 2008 Share Posted September 30, 2008 Why not just truncate an md5 of the id?! <pre><?php $a = array(); $strlen = 8; for( $i = 0; $i < 50000; $i++ ) $a[] = substr( md5($i), 0, $strlen ); $c1 = count( $a ); $c2 = count( array_unique($a) ); if( $c1 == $c2 ) echo '50000 unique entries were generated'; else echo 'Duplicates found!'; ?></pre> Though it's not guaranteed to be unique. Though with an 8 character truncation, you don't hit a collision till ~83,000 entries. Quote Link to comment Share on other sites More sharing options...
calande Posted September 30, 2008 Author Share Posted September 30, 2008 No, it has to count from 0 to ZZZZZ Quote Link to comment Share on other sites More sharing options...
discomatt Posted September 30, 2008 Share Posted September 30, 2008 Oh, sorry missed that. Hex might be easier to use in this case <pre><?php for( $i=0; $i<500; $i++ ) echo dechex( $i ) ."\n"; ?></pre> Quote Link to comment Share on other sites More sharing options...
calande Posted September 30, 2008 Author Share Posted September 30, 2008 dechex(), no, you're cheating We shouldn't be limited to the letter "f" and we need uppercase letters so that we have as many combinations with the lowest number of characters Any other suggestions? Quote Link to comment Share on other sites More sharing options...
trq Posted September 30, 2008 Share Posted September 30, 2008 So you want incrementing values? Can I ask what this is going to be used for? If its simply for testing purposes I would suggest you start trying to write it yourself, no point us testing your concepts and it is slowly getting more complex so more time consuming. Quote Link to comment Share on other sites More sharing options...
calande Posted September 30, 2008 Author Share Posted September 30, 2008 Yes, incrementing values. I don't have any concrete use right now, it is for fun but it could be used for a site like TinyURL. I am working on it right now. My code is a little cluttered, when I am done I will post it and maybe you will bring suggestions to make it more simple Quote Link to comment Share on other sites More sharing options...
discomatt Posted September 30, 2008 Share Posted September 30, 2008 Here's something that'll convert your base10 number in a base62 number... <pre><?php function newBase( $i ) { static $chars = array( '0','1','2','3','4','5','6','7','8','9', 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z', 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' ); $base = count( $chars ); $num = array(); while( $i > 0 ) { $num[] = $chars[ $i % $base ]; $i = floor( $i / $base ); } return implode( '', array_reverse($num) ); } $nums = array(); for( $i=0; $i<1000; $i++ ) $nums[] = newBase( $i ); print_r( $nums ); ?></pre> Example echo newBase( 54332646 ); returns 3FYp0 Quote Link to comment Share on other sites More sharing options...
trq Posted September 30, 2008 Share Posted September 30, 2008 I don't have any concrete use right now, it is for fun but it could be used for a site like TinyURL. You could just as easily use a random string. You'd just need to check your db for duplicates. Quote Link to comment Share on other sites More sharing options...
discomatt Posted September 30, 2008 Share Posted September 30, 2008 Same function using a string... dunno why I had an array there. function newBase( $i ) { static $chars = array( '0','1','2','3','4','5','6','7','8','9', 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z', 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' ); $base = count( $chars ); $num = ''; while( $i > 0 ) { $num .= $chars[ $i % $base ]; $i = floor( $i / $base ); } return strrev( $num ); } Quote Link to comment Share on other sites More sharing options...
calande Posted September 30, 2008 Author Share Posted September 30, 2008 discomatt: This snippet works as expected! I understand what the PHP code itself does but I don't understand the rationale...Could you explain in details and share with us please? Quote Link to comment Share on other sites More sharing options...
discomatt Posted September 30, 2008 Share Posted September 30, 2008 It uses a base x system... binary being base 2 (0,1) and hex being base 16 (0-9,a-f) This one is a base 62 (0-9,a-z,A-Z) and using the standard conversion algorithm, I converted the base 10 integer into base62 chunks and combined. This page http://mathbits.com/mathbits/compsci/Introduction/frombase10.htm summarizes the algorithm quite well visually. You divide your integer with your base, and find the integral quotient ( whole number, rounded down ) and remainder. Your remainder becomes the left most chunk. You repeat the process while your integral quotient is greater than 0... continually adding your remainder to the left of the solution. If you need more explanation let me know. Quote Link to comment Share on other sites More sharing options...
discomatt Posted September 30, 2008 Share Posted September 30, 2008 Oh and this might help a little visually print_r( $chars ); Array ( [0] => 0 [1] => 1 [2] => 2 [3] => 3 [4] => 4 [5] => 5 [6] => 6 [7] => 7 [8] => 8 [9] => 9 [10] => a [11] => b [12] => c [13] => d [14] => e [15] => f [16] => g [17] => h [18] => i [19] => j [20] => k [21] => l [22] => m [23] => n [24] => o [25] => p [26] => q [27] => r [28] => s [29] => t [30] => u [31] => v [32] => w [33] => x [34] => y [35] => z [36] => A [37] => B [38] => C [39] => D [40] => E [41] => F [42] => G [43] => H [44] => I [45] => J [46] => K [47] => L [48] => M [49] => N [50] => O [51] => P [52] => Q [53] => R [54] => S [55] => T [56] => U [57] => V [58] => W [59] => X [60] => Y [61] => Z ) So say with the number 1,345 -> Base 62 First step is divide! 1345/62 = 21 Remainder 43 [43] becomes our leftmost chunk Now our integral quotient is still above 0, so repeat! 21/62 = 0 Remainder 21 [21] takes over as our leftmost chunk, which is now [21][43] Our integral quotient is now 0, we are done. Now we convert to the desired characters above, and we get lH Now we can double check we got the right number by using 21 * (62^1) + 43 * (62^0) = 1345 We're done! Quote Link to comment Share on other sites More sharing options...
calande Posted September 30, 2008 Author Share Posted September 30, 2008 discomatt: Thanks for the link and for the explanation Quote Link to comment Share on other sites More sharing options...
discomatt Posted September 30, 2008 Share Posted September 30, 2008 Glad I can help. Wanna mark this as solved? Quote Link to comment Share on other sites More sharing options...
calande Posted September 30, 2008 Author Share Posted September 30, 2008 Yes, let's mark it as "Solved", as I doubt some one could make the snippet shorter at this point Quote Link to comment Share on other sites More sharing options...
aximbigfan Posted September 30, 2008 Share Posted September 30, 2008 Why not an MD5 of the URL? Chris Quote Link to comment Share on other sites More sharing options...
discomatt Posted September 30, 2008 Share Posted September 30, 2008 Why not an MD5 of the URL? Chris My guess is this is for database interaction. The best part about this is it's a non-numerical value, is two-way ( base10->base62->base10 ), and can be stored as a binary integer to save storage space. Quote Link to comment Share on other sites More sharing options...
Barand Posted September 30, 2008 Share Posted September 30, 2008 suppose we pick this value from the latest record in a database: H7fs, how could we ask PHP to tell us what value the next record should have? (in this case, the next record should have H7ft). $str = 'H7fs'; echo ++$str; // --> H7ft Quote Link to comment Share on other sites More sharing options...
discomatt Posted September 30, 2008 Share Posted September 30, 2008 Will eventually screw up, but I was unaware PHP could increment a mix of strings/number so damn well Thanks for that Barand. As for incrementing... gotta convert back to raw. <pre><?php $int = 123453887; $int_base62 = newBase( $int ); $int_base10 = oldBase( $int_base62 ); echo " Start: \t $int Converted: \t $int_base62 Back: \t $int_base10 "; function newBase( $i ) { static $chars = array( '0','1','2','3','4','5','6','7','8','9', 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z', 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' ); $base = count( $chars ); $num = ''; while( $i > 0 ) { $num .= $chars[ $i % $base ]; $i = floor( $i / $base ); } return strrev( $num ); } function oldBase( $str ) { static $chars = array( '0','1','2','3','4','5','6','7','8','9', 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z', 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z' ); $base = count( $chars ); $chunks = array_reverse( str_split($str) ); $i = 0; foreach( $chunks as $exp => $chunk ) { $value = array_search( $chunk, $chars ); $i += pow( $base, $exp ) * $value; } return $i; } ?></pre> And just a note - these functions are limited by your max integer size... so on a 32 bit system, these functions start returning bad results for numbers above ~2.1 billion ( signed ) Quote Link to comment Share on other sites More sharing options...
Barand Posted September 30, 2008 Share Posted September 30, 2008 Will eventually screw up, Not really $str = H7fs; for ($i=0; $i<10; $i++) echo ++$str, '<br/>'; --> H7ft H7fu H7fv H7fw H7fx H7fy H7fz H7ga H7gb H7gc and at the end of 1000 loops you have H8rx H8ry H8rz H8sa H8sb H8sc H8sd H8se and eventually you get to Z9zt Z9zu Z9zv Z9zw Z9zx Z9zy Z9zz AA0aa AA0ab AA0ac Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.