prevent Random PHP generator from including zeros - php

I have a php script that creates a random 10 digit order number:
// Assign order number length
$digits = 10;
// Create random order number to be stored with this order
$order_number = rand(pow(10, $digits-1), pow(10, $digits)-1);
How do I prevent this from ever including the digit zero 0 in the random 10 digit number? Thanks in advance!

You can do fancy base conversions, but in the end, the most straightforward way is to just get a string:
function random_string($count, $available) {
$result = '';
$max = strlen($available) - 1;
for($i = 0; $i < $count; $i++) {
$result .= $available[rand(0, $max)];
}
return $result;
}
…
$order_number = random_string($digits, '123456789');

You can treat it as a number of base 9
base_convert(rand(0, pow(9, $digits) - 1), 10, 9)
This will give you numbers with digits from 0 to 8.
Now just add 1 to every digit to make it 1 to 9
(pow(10, $digits) - 1) / 9
will give you a number filled with ones. Now just add it to your previous number and there you go:
$digits = 10;
$order_number = (pow(10, $digits) - 1) / 9 + base_convert(rand(0, pow(9, $digits) - 1), 10, 9);

Try this :D
function getRandom($from, $to){
$num = rand($from, $to);
$have_zero = true;
$strNum = strval($num);
while ($have_zero){
$have_zero = false;
for ($i = 0; $i < sizeof($strNum); $i++){
if ($strNum[$i] == '0'){
$have_zero = true;
$num = rand($from, $to);
$strNum = strval($num);
break;
}
}
}
return $num;
}
getRandom(1111111111, 9999999999);

You could use a simple function like this:
function getRandom($length) {
$numbers = '';
for($i = 0; $i < $length; $i++) {
$numbers .= rand(1, 9);
}
return $numbers;
}
echo getRandom(10);

I would make a function.
<?php
function myRandomNumberWithoutZeros($digits)
{
$result = str_replace("0", "",rand(pow(10,$digits-1), pow(10, $digits)-1)."");
$resultLength = strlen($result);
if($resultLength < $digits)
{
return intval($result.myRandomNumberWithoutZeros($digits-$resultLength));
}
return intval($result);
}
echo myRandomNumberWithoutZeros(10);
?>

Related

How to generate 16 digit number with certain prefix

I'm trying to generate 16 digit number with a specific prefix. For example, the first four-digit should be 1800
1800485480692246
This is what I achieved so far
<?php
function generatenumber($limit){
$code = '';
for($i = 0; $i < $limit; $i++) {
$code .= mt_rand(0, 9);
}
return $code;
}
echo generatenumber(16);
?>
if you want a four-digit prefix then you should generate a 12 (16-4) digit number and append the prefix to it:
function generatenumber($limit, $prefix){
$code = '';
for($i = 0; $i < $limit; $i++) {
$code .= mt_rand(0, 9);
}
return $prefix.$code;
}
echo generatenumber(12, 1800); // 1800930423128799
Or just like #pistou mentioned, to keep the 16 as input:
function generatenumber($limit, $prefix){
$code = '';
if(strlen($prefix) > strlen($limit)) {
for($i = 0; $i < ($limit - strlen($prefix)); $i++) {
$code .= mt_rand(0, 9);
}
}
return $prefix.$code;
}
This approach would also allow to have a prefix in any length, without chaning the code:
echo generatenumber(16, 1800); // 1800930423128799
echo generatenumber(16, 12345678); // 1234567841559624
See the ouput here
Based on this answer, you could do as followed:
function generateNumber($limit=16, $prefix='') {
$digits = $limit - strlen($prefix);
$rand = str_pad(rand(0, pow(10, $digits)-1), $digits, '0', STR_PAD_LEFT);
return $prefix . $rand;
}
echo generateNumber(); // 0286940312944352
echo generateNumber(10); // 5532957240
echo generateNumber(16, 1800); // 1800045386499259

Generating random values with restricted digits

What is the best way to generate a random integer with a restricted set of digits?
I want to generate a 4 digit random number, where each digit is in the range [1..6]. I was thinking generate a number in the range [0..1295], then converting to base 6 and incrementing the digits, but that goes through a string.
Without string conversion, and with only one call to a random number generator, you could do this:
function myRandom() {
$num = mt_rand(0, 1295);
$result = 0;
for ($i = 0; $i < 4; $i++) {
$result = $result*10 + $num % 6;
$num = floor($num / 6);
}
return $result + 1111;
}
You could generate each digit separately like this:
$result = '';
for ($i=0; $i < 4; $i++) {
$result .= mt_rand(1, 6);
}
$result = (int) $result;
Or if using a string is not preferred, you could do it with math:
$result = 0;
for ($i=0; $i < 4; $i++) {
$result += mt_rand(1, 6) * 10 ** $i;
// or for PHP versions < 5.6 (no ** exponentiation operator)
// $result += mt_rand(1, 6) * pow(10, $i);
}
<?php
// 216_10 = 1000_6
// 1295_10 = 5555_6
base_convert(mt_rand(216,1295),10,6);

Divide integer number into dynamic number of parts using php

I want to divide a number into n number of parts like follows
Input : $n = 4;$m =14;
Output should as : array(1=>4,2=>4,3=>3,4=>3);
i.e :
$n $m
1 1+1+1+1
2 1+1+1+1
3 1+1+1
4 1+1+1
Any suggestions or links would help a lot.
Here is one way to do it - this works in phpfiddle:
$n = 4;
$m =14;
$array = distribute($m,$n);
print_r($array);
function distribute($m,$n) {
$div = floor($m / $n);
$mod = fmod($m, $n);
$result = array();
for ($i = 1;$i <= $n;$i++) {
$result[$i] = $div;
}
if ($mod > 0) {
for ($i = 1;$i <= $mod;$i++) {
$result[$i] = $result[$i] + 1;
}
}
return $result;
}

PHP Function To Get Character Number

How can I write a function that gives me number of the character that is passed to it
For example, if the funciton name is GetCharacterNumber and I pass B to it then it should give me 2
GetCharacterNumber("A") // should print 1
GetCharacterNumber("C") // should print 3
GetCharacterNumber("Z") // should print 26
GetCharacterNumber("AA") // should print 27
GetCharacterNumber("AA") // should print 27
GetCharacterNumber("AC") // should print 29
Is it even possible to achieve this ?
There is a function called ord which gives you the ASCII number of the character.
ord($chr) - ord('A') + 1
gives you the correct result for one character. For longer strings, you can use a loop.
<?php
function GetCharacterNumber($str) {
$num = 0;
for ($i = 0; $i < strlen($str); $i++) {
$num = 26 * $num + ord($str[$i]) - 64;
}
return $num;
}
GetCharacterNumber("A"); //1
GetCharacterNumber("C"); //3
GetCharacterNumber("Z"); //26
GetCharacterNumber("AA"); //27
GetCharacterNumber("AC"); //29
GetCharacterNumber("BA"); //53
?>
Not very efficient but gets the job done:
function get_character_number($end)
{
$count = 1;
$char = 'A';
$end = strtoupper($end);
while ($char !== $end) {
$count++;
$char++;
}
return $count;
}
echo get_character_number('AA'); // 27
demo
This works because when you got something like $char = 'A' and do $char++, it will change to 'B', then 'C', 'D', … 'Z', 'AA', 'AB' and so on.
Note that this will become the slower the longer $end is. I would not recommend this for anything beyond 'ZZZZ' (475254 iterations) or if you need many lookups like that.
An better performing alternative would be
function get_character_number($string) {
$number = 0;
$string = strtoupper($string);
$dictionary = array_combine(range('A', 'Z'), range(1, 26));
for ($pos = 0; isset($string[$pos]); $pos++) {
$number += $dictionary[$string[$pos]] + $pos * 26 - $pos;
}
return $number;
}
echo get_character_number(''), PHP_EOL; // 0
echo get_character_number('Z'), PHP_EOL; // 26
echo get_character_number('AA'), PHP_EOL; // 27
demo
Use range and strpos:
$letter = 'z';
$alphabet = range('a', 'z');
$position = strpos($alphabet, $letter);
For double letters (eg zz) you'd probably need to create your own alphabet using a custom function:
$alphabet = range('a', 'z');
$dictionary = range('a','z');
foreach($alphabet AS $a1){
foreach($alphabet AS $a2) {
$dictionary[] = $a1 . $a2;
}
}
Then use $dictionary in place of $alphabet.
Here is the full code that does what you want.
Tested it and works perfectly for the examples you gave.
define('BASE', 26);
function singleOrd($chr) {
if (strlen($chr) == 1) {
return (ord($chr)-64);
} else{
return 0;
}
}
function multiOrd($string) {
if (strlen($string) == 0) {
return 0;
} elseif (strlen($string) == 1) {
return singleOrd($string);
} else{
$sum = 0;
for($i = strlen($string) - 1; $i >= 0; $i--) {
$sum += singleOrd($string[$i]) * pow(BASE, $i);
}
}
return $sum;
}
I think ord should be a more efficient way to have your number :
$string = strtolower($string);
$result = 0;
$length = strlen($string);
foreach($string as $key=>$value){
$result = ($length -$key - 1)*(ord($value)-ord(a)+1);
}
and result would contain what you want.

Auto incrementing unique url

I am looking to create an auto incrementing unique string using PHP, containing [a-Z 0-9] starting at 2 chars long and growing when needed.
This is for a url shrinker so each string (or alias) will be saved in the database attached to a url.
Any insight would be greatly appreciated!
Note this solution won't produce uppercase letters.
Use base_convert() to convert to base 36, which will use [a-z0-9].
<?php
// outputs a, b, c, ..., 2o, 2p, 2q
for ($i = 10; $i < 99; ++$i)
echo base_convert($i, 10, 36), "\n";
Given the last used number, you can convert it back to an integer with intval() increment it and convert the result back to base 36 with base_convert().
<?php
$value = 'bc9z';
$value = intval($value, 36);
++$value;
$value = base_convert($value, 10, 36);
echo $value; // bca0
// or
echo $value = base_convert(intval($value, 36) + 1, 10, 36);
Here's an implementation of an incr function which takes a string containing characters [0-9a-zA-Z] and increments it, pushing a 0 onto the front if required using the 'carry-the-one' method.
<?php
function incr($num) {
$chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$parts = str_split((string)$num);
$carry = 1;
for ($i = count($parts) - 1; $i >= 0 && $carry; --$i) {
$value = strpos($chars, $parts[$i]) + 1;
if ($value >= strlen($chars)) {
$value = 0;
$carry = 1;
} else {
$carry = 0;
}
$parts[$i] = $chars[$value];
}
if ($carry)
array_unshift($parts, $chars[0]);
return implode($parts);
}
$num = '0';
for ($i = 0; $i < 1000; ++$i) {
echo $num = incr($num), "\n";
}
If your string was single case rather than mixed, and didn't contain numerics, then you could literally just increment it:
$testString="AA";
for($x = 0; $x < 65536; $x++) {
echo $testString++.'<br />';
}
$testString="aa";
for($x = 0; $x < 65536; $x++) {
echo $testString++.'<br />';
}
But you could possibly make some use of this feature even with a mixed alphanumeric string
To expand on meagar's answer, here is how you can do it with uppercase letters as well and for number arbitrarily big (requires the bcmath extension, but you could as well use gmp or the bigintegers pear package):
function base10ToBase62($number) {
static $chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$result = "";
$n = $number;
do {
$remainder = bcmod($n, 62);
$n = bcdiv($n, 62);
$result = $chars[$remainder] . $result;
} while ($n > 0);
return $result;
}
for ($i = 10; $i < 99; ++$i) {
echo base10ToBase62((string) $i), "\n";
}

Categories