Basically I'm working on a card management system in a particular module that has the job of creating bulk cards that are sequential. These cards are 19 digits long and because these cards have a monetary value I need to store the entire card value. The odd thing is that the system has no trouble managing VISA card number incrementing and those are 16 digits long. I'm assuming those last 3 digits are what is breaking the function but I have no idea how on Earth to handle this as I've never had to deal with such large values before.
$seqArray = array();
for($i = $_POST['startcardnumber']; $i <= $_POST['endcardnumber']; $i++) {
$i = sprintf('%0.0f',$i);
if(strlen($i) < $count) { $i = str_pad($i, $count, '0', STR_PAD_LEFT); }
array_push($seqArray, $i);
}
Any help is much appreciated.
Thanks to Fluffeh I found out that the BC Math functions were exactly what I needed. Below is the new for loop that I'm using to calculate and increment card numbers.
$seqArray = array();
for($s = $_POST['startcardnumber'], $e = $_POST['endcardnumber'];bccomp($s,$e) != 1; $s = bcadd($s, 1)) {
if(strlen($s) < $count) { $s = str_pad($s, $count, '0', STR_PAD_LEFT); }
array_push($seqArray, $s);
}
The BC Math library might be a little tedious to work with, but it will handle numbers in values you need with ease.
The downside is that you can't use simple things operators as expected:
For example, addition is done as the following - using the bcadd() function:
<?php
$a = '1.234';
$b = '5';
echo bcadd($a, $b); // 6
echo bcadd($a, $b, 4); // 6.2340
?>
Related
I'm trying to distribute 100% to total numbers (not equally), it can be done manually but I'm looking for a automatically way in PHP. I had to open calculator and get it done for manual.
What I'm trying to achieve is the result similar to this:
$value = 10000;
$total_numbers = 9
$a1 = $value*0.2;
$a2 = $value*0.175;
$a3 = $value*0.15;
$a4 = $value*0.125;
$a5 = $value*0.1;
$a6 = $value*0.08;
$a7 = $value*0.07;
$a8 = $value*0.05;
$a9 = $value*0.04;
So as you can see, the first variables have more quantity than the later ones, but if you add these, it will be 1 which is 100%. So lets say I have total_numbers=20 then I'll have to re-write it and get a calculator and do it the hard way to accomplish my goal. Is there any way this can be done automatically with a function where I can just tell the total number and it can distribute it to proportions or something?
The first one will always be bigger than rest, then second one bigger than rest but smaller than first, third one being greater than rest but small than first and second, and so on.
function distributeValue($value, $num) {
$parts = $num * ($num + 1) / 2;
$values = [];
for ($i = $num; $i > 1; --$i) {
$values[] = round($value * $i / $parts);
}
$values[] = $value - array_sum($values);
return $values;
}
var_dump(distributeValue(10000, 9));
This works by calculating the $numth triangle number (the number you get by adding all the numbers from 1 to $num) and dividing the total value up into this number of parts.
It then starts by taking $num parts, then $num-1 parts and so on.
Since it's rounding the numbers, the last step is to take the total minus all the other values which is around one part. If you are fine with getting floats instead of ints out, then you can remove the $values[] = $value - array_sum($values); line and change the condition of the for loop to $i > 0.
I am new to PHP and stackoverflow and try to figure things out for myself before asking but I am having a little trouble doing some maths on an array I have pulled from a database with PHP.
So far I have an array of numbers called $array['sn']
I have created a function in excel that does the maths and works well in excel but I cant figure out a way to do it in PHP.
the excel function is =QUOTIENT(E32,65536)"IENT(E32-F34*65536,256)&(G33-G35*256)
E32 being the value I start with i.e $sn
F34 being the answer to the first quotient
G35 being the answer to the second quotient
G33 being E32-F34*65536
I want to take a number e.g. 3675177 divide it by 65536 but without the remainder which is 56, then multiply 56 by 65536 which equals 3670016, then find the difference between 3670016 and 3675177 which is 5161. Then divide 5161 by 256 with no remainder which is 20 then multiply 20 by 256 and subtract 5161 which is 41.
The end result from 3675177 should be 562041. I want to do this calculation on every number in the $array['sn'], any help would be appreciated.
The calculation and formatting of the output would be like this:
$n = 3675177;
$const = 65536;
$const2 = 256;
$a = intval($n / $const); // intval returns only the integer part of a number
$x = $n % $const; // $n % $const means "the remainder of $n / $const"
$b = intval($x / $const2);
$c = $x % $const2;
// Two options to handle values of $c < 10:
// if ($c < 10) $c = "0$c";
// $c = str_pad($c, 2, "0", STR_PAD_LEFT);
echo "$a$b$c";
I would recommend using array_map to apply the calculation to your array of values.
There are php arithmetic operations you can use.
I would do something like this:
$initialNumber = //the initial number, wherever you get it from
$entireDivision = ceil($initialNumber/65536)-1;
$remainder = $initialNumber%65536;
$remainderMultiplied = $remainder * 56;
$difference = $initialNumber - $remainderMultiplied;
$differenceDivided = ceil($difference/256)-1;
$differenceMultipliedAndSubstracted = ($differenceDivided * 256) - $difference;
Maybe I used too many variables, this is to be a bit more easy to understand for you. Maybe I did some operation wrong, check it out too. But this is the idea of mathematic operations in php. Maybe you should put this inside a php function with parameters, so your code gets cleaner if you use multiple times.
EDIT: You should put this code inside a function, then run a foreach loop in your array running this function taking as parameter the value of the array position.
$results = array();
foreach ($array['sn'] as $key => $a) {
$b = intval($a / 65536);
$c = ($a - $b * 65536);
$d = intval($c / 256);
$e = $c - $d * 256;
$results[$key] = $b . $d . $e;
}
var_dump($results);
I need to generate x amount of random odd numbers, within a given range.
I know this can be achieved with simple looping, but I'm unsure which approach would be the best, and is there a better mathematical way of solving this.
EDIT: Also I cannot have the same number more than once.
Generate x integer values over half the range, and for each value double it and add 1.
ANSWERING REVISED QUESTION: 1) Generate a list of candidates in range, shuffle them, and then take the first x. Or 2) generate values as per my original recommendation, and reject and retry if the generated value is in the list of already generated values.
The first will work better if x is a substantial fraction of the range, the latter if x is small relative to the range.
ADDENDUM: Should have thought of this approach earlier, it's based on conditional probability. I don't know php (I came at this from the "random" tag), so I'll express it as pseudo-code:
generate(x, upper_limit)
loop with index i from upper_limit downto 1 by 2
p_value = x / floor((i + 1) / 2)
if rand <= p_value
include i in selected set
decrement x
return/exit if x <= 0
end if
end loop
end generate
x is the desired number of values to generate, upper_limit is the largest odd number in the range, and rand generates a uniformly distributed random number between zero and one. Basically, it steps through the candidate set of odd numbers and accepts or rejects each one based how many values you still need and how many candidates still remain.
I've tested this and it really works. It requires less intermediate storage than shuffling and fewer iterations than the original acceptance/rejection.
Generate a list of elements in the range, remove the element you want in your random series. Repeat x times.
Or you can generate an array with the odd numbers in the range, then do a shuffle
Generation is easy:
$range_array = array();
for( $i = 0; $i < $max_value; $i++){
$range_array[] .= $i*2 + 1;
}
Shuffle
shuffle( $range_array );
splice out the x first elements.
$result = array_slice( $range_array, 0, $x );
This is a complete solution.
function mt_rands($min_rand, $max_rand, $num_rand){
if(!is_integer($min_rand) or !is_integer($max_rand)){
return false;
}
if($min_rand >= $max_rand){
return false;
}
if(!is_integer($num_rand) or ($num_rand < 1)){
return false;
}
if($num_rand <= ($max_rand - $min_rand)){
return false;
}
$rands = array();
while(count($rands) < $num_rand){
$loops = 0;
do{
++$loops; // loop limiter, use it if you want to
$rand = mt_rand($min_rand, $max_rand);
}while(in_array($rand, $rands, true));
$rands[] = $rand;
}
return $rands;
}
// let's see how it went
var_export($rands = mt_rands(0, 50, 5));
Code is not tested. Just wrote it. Can be improved a bit but it's up to you.
This code generates 5 odd unique numbers in the interval [1, 20]. Change $min, $max and $n = 5 according to your needs.
<?php
function odd_filter($x)
{
if (($x % 2) == 1)
{
return true;
}
return false;
}
// seed with microseconds
function make_seed()
{
list($usec, $sec) = explode(' ', microtime());
return (float) $sec + ((float) $usec * 100000);
}
srand(make_seed());
$min = 1;
$max = 20;
//number of random numbers
$n = 5;
if (($max - $min + 1)/2 < $n)
{
print "iterval [$min, $max] is too short to generate $n odd numbers!\n";
exit(1);
}
$result = array();
for ($i = 0; $i < $n; ++$i)
{
$x = rand($min, $max);
//not exists in the hash and is odd
if(!isset($result{$x}) && odd_filter($x))
{
$result[$x] = 1;
}
else//new iteration needed
{
--$i;
}
}
$result = array_keys($result);
var_dump($result);
For an ecommerce site I want to generate a random coupon code that looks better than a randomly generated value. It should be a readable coupon code, all in uppercase with no special characters, only letters (A-Z) and numbers (0-9).
Since people might be reading this out / printing it elsewhere, we need to make this a simple-to-communicate value as well, perhaps 8-10 characters long.
Something like perhaps,
AHS3DJ6BW
B83JS1HSK
(I typed that, so it's not really that random)
$chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$res = "";
for ($i = 0; $i < 10; $i++) {
$res .= $chars[mt_rand(0, strlen($chars)-1)];
}
You can optimize this by preallocating the $res string and caching the result of strlen($chars)-1. This is left as an exercise to the reader, since probably you won't be generating thousands of coupons per second.
Try this:
substr(base_convert(sha1(uniqid(mt_rand())), 16, 36), 0, 10)
Why don't keep it simple?
<?php
echo strtoupper(uniqid());
?>
Always returns 13 character long uppercased random code.
You can use the coupon code generator PHP class file to generate N number of coupons and its customizable, with various options of adding own mask with own prefix and suffix. Simple PHP coupon code generator
Example:
coupon::generate(8); // J5BST6NQ
http://webarto.com/35/php-random-string-generator
Here you go.
function randr($j = 8){
$string = "";
for($i=0;$i < $j;$i++){
srand((double)microtime()*1234567);
$x = mt_rand(0,2);
switch($x){
case 0:$string.= chr(mt_rand(97,122));break;
case 1:$string.= chr(mt_rand(65,90));break;
case 2:$string.= chr(mt_rand(48,57));break;
}
}
return strtoupper($string); //to uppercase
}
If there are no security requirements for these, then you don't really need randomly generated codes. I would just use incremental IDs, such as those generated by whatever RDBMS you use. Optionally, if you have different types of coupons, you could prefix the codes with something, e.g.:
CX00019 QZ0001C
CX0001A QZ0001D
CX0001B QZ0001E
Alternately, you could even use dictionary words in the coupon, as such coupon codes are easier to remember and faster for users to type. Companies like Dreamhost use these for their promo codes, e.g.:
Promo60
NoSetupFee
YELLOWGORILLA82
Some of these are obviously human-created (which you might want to have the option of), but they can also be generated using a dictionary list. But even if they are randomly-generated nonsense phrases, the fact that the characters follow a logical pattern still makes it much more user-friendly than something like R7QZ8A92F1. So I would strongly advise against using the latter type of coupon codes just on the basis that they "look cool". Your customers will thank you.
$size = 12;
$string = strtoupper(substr(md5(time().rand(10000,99999)), 0, $size));
function generateCouponCode($length = 8) {
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
$ret = '';
for($i = 0; $i < $length; ++$i) {
$random = str_shuffle($chars);
$ret .= $random[0];
}
return $ret;
}
you can find a lot of function in php rand manual
http://php.net/manual/en/function.rand.php
i like this one
<?php
//To Pull 8 Unique Random Values Out Of AlphaNumeric
//removed number 0, capital o, number 1 and small L
//Total: keys = 32, elements = 33
$characters = array(
"A","B","C","D","E","F","G","H","J","K","L","M",
"N","P","Q","R","S","T","U","V","W","X","Y","Z",
"1","2","3","4","5","6","7","8","9");
//make an "empty container" or array for our keys
$keys = array();
//first count of $keys is empty so "1", remaining count is 1-7 = total 8 times
while(count($keys) < 8) {
//"0" because we use this to FIND ARRAY KEYS which has a 0 value
//"-1" because were only concerned of number of keys which is 32 not 33
//count($characters) = 33
$x = mt_rand(0, count($characters)-1);
if(!in_array($x, $keys)) {
$keys[] = $x;
}
}
foreach($keys as $key){
$random_chars .= $characters[$key];
}
echo $random_chars;
?>
$length = 9;
$code = (strtoupper(substr(md5(time()), 0, $length)));
Just Write
$voucher_no = date('ymd') . rand(1000, 9999);
while(SapItem::where('voucher_no', $voucher_no)->exists()){
$voucher_no = date('ymd') . rand(1000, 9999);
}
Output: 2204171447
Unfortunately I inherited some code (c/c++) that does some string manipulation and now I need to copy/port that over to php so this functionality can be accessed over the internets.
Specifically the functionality takes some arbitrary strings and "adds" them together. (the c code iterates down the character array and then does some checking to make sure they are in the alphanumeric range)
I can't find specific code examples on how to do this (I am not a PHP developer) - can anyone point me to some resources that will explain this? (basically how to do string/character array manipulation)
EDIT
In response to some comments and answers:
I want the result in ascii, but essentially I will be adding base 36 numbers.
The C code right now converts to base 36 (from ascii)
then "adds" each element together (does not carry - although the original author intended that - and it for some strange reason does the "add" from most significant to least)
Then converts back to ascii.
Strings can be of different lengths
Based on the current answers i think I have enough of what I need. It is always frustrating sometimes learning a new language - you know exactly what you want and you can do it in other languages, just not the one that is for the task at hand...
Thanks for the responses so far.
Can't you just base_convert() them?
$sum = base_convert($str1, 36, 10) + base_convert($str2, 36, 10);
$sum36 = base_convert($sum, 10, 36);
Or do you need arbitrary precision? Here's a stab at arbitrary precision addition, in base 36:
function b36_add($str1, $str2)
{
$to10 = array();
for ($i = 0; $i < 36; ++$i)
{
$to10[base_convert($i, 10, 36)] = $i;
}
$len = max(strlen($str1), strlen($str2));
$str1 = str_repeat('0', $len - strlen($str1)) . $str1;
$str2 = str_repeat('0', $len - strlen($str2)) . $str2;
$pos = $len - 1;
$carry = 0;
$sum = '';
do
{
$tmp = base_convert($carry + $to10[$str1[$pos]] + $to10[$str2[$pos]], 10, 36);
$sum .= substr($tmp, -1);
$carry = (int) substr($tmp, 0, -1);
}
while (--$pos >= 0);
$sum = strrev($sum);
if ($carry)
{
$sum = base_convert($carry, 10, 36) . $sum;
}
return $sum;
}
If you have a string like this in php you can just call the index of an individual character like so:
<?
$x = "Hello";
print $x[0] . "\n";
So in other words, $string_var[n] gives you the nth char, 0-indexed.
First off, I'm assuming you want to add ascii values.
ord() might help you. Based on the other answer, something like:
<?php
function addStrings($x, $y){
// Assumes that both strings are the same length
for($i=0; $i<strlen($x); $i++){
$result[i] = ord($x[i]) + ord($y[i]);
}
return $result;
}
?>
If you use this, you'll probably want to do something if $x and $y are different lengths, but I think it gets the idea across.