Unable to generate sequence wise unique number along with day in PHP - php

in my code I have a product uploading system, I want every time I upload a product it would have a unique product code.I'm using PHP CodeIgniter framework. I've done everything e.g the end two digits of the year and the count of days out of 365 days but unable to generate serial number like 1865001 then 1865002 then 1865003.
Below is the code of my controller
public function view(){
$data['subview'] = 'admin/parts/user_list';
$data['title'] = 'User Overview';
$data['users'] = $this->Users_model->get_users();
//Code Generator
$this->load->helper('string');
$y= substr(date('Y'),2);
$t = date('z') + 1;
$data['codes'] = $y.$t;
$this->load->view('admin/__layout_admin.php', $data);
print_r($data['codes']);
}
The current output is 1865.
I want it should be like 1865001,1865002,1865003,1865004.
Please help me doing this.

First of all, numbers should be like 18065001, note the zero between 18 and 65, cause when you reach day 100th you will keep the length.
Also, you will need a daily counter to generate sequential part (001, 002, ..), I would store that counter in a database so u can update every time u generate a product and reset it when a new day coming up.
So the code could be something like:
public function view(){
$data['subview'] = 'admin/parts/user_list';
$data['title'] = 'User Overview';
$data['users'] = $this->Users_model->get_users();
//Code Generator
$this->load->helper('string');
$y= substr(date('Y'),2);
$t = date('z') + 1;
// fill one one zero if year is less than 100
$t = 2 == strlen($t) ? '0' . $t : $t;
$counter = $this->ProductCounter_model->get_counter();
$data['codes'] = $y . $t . sprintf('%03d', $counter + 1);
$this->load->view('admin/__layout_admin.php', $data);
print_r($data['codes']);
}
So in $data['counter'] you will receive the current counter and when you store the product you should update the counter in the database. Don't forget to reset the counter to zero at midnight.
And if it is not strictly necessary to have correlative numbers (001, 002, 003) I will use the number of seconds from midnight which would simplify the process and avoid to save and reset the counter and also pass it as a parameter in data, in that case, you can change this line:
$data['codes'] = $y . $t. sprintf('%05d', echo time() -
strtotime("today"));
You need 5 space for the greatest number of second from one day, 86400 seconds.

Related

Trading view vs Binance DMI calculation?

I'm trying to calculate the directional movement indicator for 5m interval using the API of Binance. I'm using 288 values of "High", "Open" and "Close" and
I'm calculating the True range and then the Average True Range (ATR) with a simple moving average of a window with 14 values. I'm using the same Simple Moving average technique
for the calculation of the +DI, -DI and the ADX, but the values that I get don't match the ones that are shown in trading view for the DMI. I have also tried using an
exponential moving average the ATR, the +Di and the -DI, but I still don't get matching values. I have also noticed that the DMI of Binance and Trading view do not match.
Do you know which smoothing techinique is used by the DMI of trading view?
$url = 'https://api.binance.com/api/v3/klines?symbol=BNBBTC&interval=5m&limit=288';
$candles = file_get_contents($url);
$candles = json_decode($candles, true);
$arr_results = array();
$high = array();
$low = array();
$close_arr = array();
$average = array();
for($i= 0; $i < sizeof($candles); $i++){
array_push($high, $candles[$i][2]);
array_push($low, $candles[$i][3]);
array_push($close_arr, $candles[$i][4]);
$av = ($candles[$i][2] + $candles[$i][3]) /2;
array_push($average, $av);
}
$plus_di = array_pop(trader_plus_di($high, $low, $close_arr, 14));
$minus_di = array_pop(trader_minus_di($high, $low, $close_arr, 14));
$adx = array_pop(trader_adx ($high, $low, $close_arr, 14));
To calculate the ATR, you need to smooth the TR (True Range) according to the following method :
Take a smoothing period nbCandles (nbCandles=14 candles typically), then:
First ATR value: ATR(1) = Sum{TR(1 -> nbCandles)} (i.e you sum the nbCandles first values of the TR to get your first value of the ATR) - If nbCandles = 14 then your first ATR value will be the sum of the first 14 values of TR.
Then, for the following ATR values, you use the following formula:
ATR(i) = ATR(i-1) - ATR(i-1)/nbCandles + TR(i)
Here is an example (based on 30 1 minutes candles historical record and 14 as the smoothing factor (number of candles used for smoothing)) :
Binance BTCUSDT 1m

Laravel 5.6 custom id with mutator reset counter everyday

I use a mutator to create a custom id for my records to make it look like this:
yyyy-mm-dd-{sequence}
The sequence looks like this
00001
00002
...
So it's 5 digits and is just a counter.
I have 2 problems
1) I don't know how to create a counter in my mutator, I can do a for loop but I don't now how to make an infinte loop that resets when it's tomorrow.
2) I honestly have no idea how to make it reset every day.
My mutator:
public function setFunctionalIdAttribute($id)
{
$date = Carbon::now()->format("Y-m-d");
// I take an extremely large number here because there will never be so much records in 1 day.
for ($counter = 0; $counter <= 100000000000; $counter++) {
$counter = str_pad($counter, 5, '0', STR_PAD_LEFT);
}
$today = Carbon::today();
$tomorrow = Carbon::tomorrow();
if ($today = $tomorrow) {
$counter = 0;
}
$this->attributes['functional_id'] = $date . "-" . $counter;
}
Its hard to say it but, in the nicest possible way, your counter loop doesn't really make any sense, I'm sorry! I'd recommend getting rid of that entirely, or at least read the PHP docs on str_pad.
You also have a conditional statement that checks "is today tomorrow". That to me is a big red flag that the logic, in general, isn't correct.
Let's think through an alternative. You're essentially counting the number of records in a day, to use that as the ID. I'd suggest an approach similar to this:
public function setFunctionalIdAttribute()
{
// 1. Count how many records there are from today
// 2. Make an ID that is this number + 1
// 3. If need be, string pad left with 0's
}
1. Count how many records there are from today
Laravel has a handy whereDate function – from the docs (search for whereDate)
$count = DB::table('users')
->whereDate('created_at', Carbon::today()->toDateString())
->count();
So if we had 3 records made today, $count would be 3.
2. Make an ID that is this number + 1
$count ++;
3. If need be, string pad left with 0's
The PHP docs on str_pad are pretty terrible, lets just cover the basics:
str_pad($input, $length, $pad_string, $pad_type);
$input is the string you are padding
$length is the final length of the string (this is why your for loop was totally unnecessary)
$pad_string if the string length is less than $length, fill up the remaining space with this
$pad_type as you rightly had, is an optional flag to pad left
Your $input is the $count, your $length is 5, judging from your example, $pad_string is "0", and we keep PAD_LEFT.
$id = str_pad($count, 5, "0", PAD_LEFT)
I can't remember how to set an attribute through a mutator so just copying your example (I hope that's correct!) we get:
public function setFunctionalIdAttribute()
{
$count = DB::table('users') // Remember to change this to the correct table name
->whereDate('created_at', Carbon::today()->toDateString())
->count();
$count ++;
$id = str_pad($count, 5, PAD_LEFT)
$this->attributes['functional_id'] = $id;
}
Remember to only do this on create, as we don't want to increment this ID on every save.
I don't know the purpose of your code, but this will allways set "functional_id" to something like "2019-01-23-100000000001", since you are using the $counter variable out of your loop.
Your loop is looping trough without doing anything. (And why the hell are you looping till such a high number if you are not expecting more than 100000 entries?!?)
What you need is the previous counter you have set, ether from DB or somewhere else, but like this your code is not going to work.
In that way you could perform some check like
if ($dateOfLastEntry != Carbon::now()->format('Y-m-d')) {$counter = 1}
otherwise set $counterOfLastEntry + 1
not using that scary for-loop you are using
str_pad performed at the end
Maybe you give us a little more information how this should work, for what you are going to use that counter, and where you are going to store this data.
I know it is a old question, but for everybody that needs something like it for days to come, I made something that resolve the question.
public function Counter()
{
$today = Carbon::today();
$today_files = Shipment::whereDate('created_at', $today)->count();
$counter= $today_files;
if ($today_files != 0) {
$counter++;
} else {
$counter = 1;
}
return counter;
}```

Given array of 1000 strings wih an associated time-interval value X for each, how do I perform a task for each of the strings, every x minutes?

I have a thousand (for example, could be more) strings and for each string, there is a field associated with it which represents time interval.
For each one of the strings, I need to perform a task which takes the string as input and produces some output, every X minutes (X being the time interval mentioned above).
If it was a single value of time interval for all the strings, then I would set up a single cron job and that would suffice; but I have a different value of time interval for each of the strings.
So I'll set up a thousand or more cron jobs. That does not feel right. So what would be the best way to solve this problem?
You might want to look into using a library that already did this instead of re-inventing the wheel yourself.
https://packagist.org/packages/peppeocchi/php-cron-scheduler
But, if you'd really want to code it yourself you'll need to have "two variables" one with last executed which has to be read from a file or database in between execution cycles, one with interval and have cron call your script every second/minute
Take a look at the proof of concept code here. Untested but it should point you in to how it should work in theory.
class Job
{
protected $interval = 0;
protected $lastrun = 0;
protected $job = null;
protected $filename = null;
public function __construct($id, $interval,callable $job)
{
$this->interval = $interval;
$this->job = $job;
$this->filename = __DIR__.'/'.$id.'.job';
$this->lastrun = file_get_contents($this->filename) ? : 0;
}
public function attemptRun($time)
{
if($time - $this->lastrun >= $this->interval) {
$this->run($time);
}
}
protected function run($time)
{
file_put_contents($this->filename, $time);
$this->job();
}
}
$jobs = [
new Job('addition', 10, function() { $a = 1; $b = 2; $c = $a + $b;}),
new Job('subtraction', 20, function() { $a = 1; $b = 2; $c = $a - $b;}),
];
var $currentTime = time();
foreach($jobs as $job) {
$job->attemptRun($currentTime);
}
Cron job: Run it every minute.
Let's say you have 3 strings in the format string_value-execute after certain minutes-
some_string-5
some_string_2-10
some_string_3-15
So, execution time if we start from 0 will have a series like this-
0
5 (execute first)
10 (execute first as well as second string)
15 (execute first and third string)
20 (execute first as well as second string)
25 (execute only first)
30 (execute first,second,third)
Database part:
Have 2 tables.
First table- has a single column having current cron minute.
second table- Have column as string , interval duration , next_execution_time
Now, insert into first table whenever you run it.
Secondly, do a "Select * from table_name where next_execution_time = current_got_fetched_from_first_table".
Introduce new strings- When you are doing so, insert as first start interval = current_cron_time + interval_duration to execute.
P.S- When processing completes, you also need to update the second table with their respective next_execution_time.

how to generate unique random numbers in php?

I am generating random numbers using php random function, but I want the generated number should be unique and it should not be repeated again.
----------
php code
$number = rand(100,100000); //a six digit random number between 100 to 100000
echo $number;
----------
but I am using this function for multiple times in my code for users so at very rare case there should be a chance of generating same number again. how can i avoid that.
I would do this:
You said you have branches. The receipt id could look something like this:
$dateString = date('Ymd'); //Generate a datestring.
$branchNumber = 101; //Get the branch number somehow.
$receiptNumber = 1; //You will query the last receipt in your database
//and get the last $receiptNumber for that branch and add 1 to it.;
if($receiptNumber < 9999) {
$receiptNumber = $receiptNumber + 1;
}else{
$receiptNumber = 1;
}
Update the receipt database with the receipt number.
$dateString . '-' . $branchNumber . '-' . $receiptNumber;
This will read:
20180406-101-1
This will be unique(Provided you do less than 10,000 transactions a day.) and will show your employees easily readable information.
If you are storing users in DB you should create column [ID] as primary key with auto increment and that would be best solution.
In other case I'd recommend you to simply store all user id's in ascending order from N to M by reading last ID and adding 1 to it because I see no real gain from random order that only adds complexity to your code.
There are many ways, example:
$freq = [];
$number = rand(100,100000);
$times = 10;
while($times-- > 0)
{
while(in_array($number, $freq))$number = rand(100,100000);
$freq[] = $number;
echo $number . "<br>";
}
This will print 10 random unique numbers.
random_int
(PHP 7)
<?php
$number = random_int(100, 100000);
echo $number;
All you need to do is use timestamp in php as timestamp never cross each other hence it will always generate unique number.You can use time() function in php.
The time() function is used to format the timestamp into a human desired format. The timestamp is the number of seconds between the current time and 1st January, 1970 00:00:00 GMT. It is also known as the UNIX timestamp.
<?php
$t=time();
echo $t;
?>
Also you add a rand() function and insert it in front of the $t to make it more random as if few users work at same time then the timestamp might collide.
<?php
$number = rand(100,100000);
$t=time();
$random = $number.''.$t;
echo $random;
?>
The above will reduce the chance to timestamp collide hence making the probability of number uniqueness almost 100%.
And if you make your column unique in your database then the php wont insert the number hence this bottleneck will ensure you will always get a unique random number.
bill_id not null unique
If you are using it for something like user id, then you can use uniqid for that. This command gets a prefixed unique identifier based on the current time in microseconds.
Here's how to use it:
string uniqid ([ string $prefix = "" [, bool $more_entropy = FALSE]] )
Where prefix is used if you are generating ids for a lot if hosts at the same time, you can use this to differentiate between various hosts if id is generated at the same microsecond.
more_entropy increases the likeness of getting unique values.
Usage:
<?php
/* A uniqid, like: 4b3403665fea6 */
printf("uniqid(): %s\r\n", uniqid());
/* We can also prefix the uniqid, this the same as 
 * doing:
 *
 * $uniqid = $prefix . uniqid();
 * $uniqid = uniqid($prefix);
 */
printf("uniqid('php_'): %s\r\n", uniqid('php_'));
/* We can also activate the more_entropy parameter, which is 
 * required on some systems, like Cygwin. This makes uniqid()
 * produce a value like: 4b340550242239.64159797
 */
printf("uniqid('', true): %s\r\n", uniqid('', true));
?>
this code must work
some description about code:
generate unique id
extract numbers form unique id with regex
gathering numbers from regex with a loop
<?php
$unique = uniqid("",true);
preg_match_all("!\d+!", $unique ,$matches);
print_r($matches);
$numbers = "";
foreach($matches[0] as $key => $num){
$numbers .= $num;
}
echo $numbers;

PHP Generate Unique Order Number with Date

I want to generate unique identificator in following 12 numeric format:
YYYYMMDDXXXX
Example:
201403052318
Where:
YYYYMMDD is a current date value and other XXXX is randomly generated value.
$today = date("Ymd");
$rand = sprintf("%04d", rand(0,9999));
$unique = $today . $rand;
Daily required unique volume is about 100. What methods using PHP should I use to prevent possible duplicates in rand values or make all id maximum unique? Maybe possible use current time functions to compact these numbers in last 4 characters?
EDITED:
Unique value connected to MySQL database as prime index of table. It is initial values not connected to any stored information in database.
You can't rely on rand() , There is a possibility you will generate a duplicate (Pretty rare for a rand(0,9999) to generate a duplicate, but that will at some point).
So instead of going for rand(), just create an incremental value (say.. starting from 1) and append to your generated date.
Next time when you regenerate a new id, grab that incremental value's (say if you had stored it somewhere.. must be 1 right ?) status, increment it and append it to your new date.
Not an ideal solution.. (Critics welcome)
You can make use of a uniqid coupled with sha-1 and time and do a substr() on them for first 4 chars.
<?php
$today = date("Ymd");
$rand = strtoupper(substr(uniqid(sha1(time())),0,4));
echo $unique = $today . $rand;
OUTPUT :
201403094B3F
I needed to do something similar, a solution that would keep time and also keep the id unique and i ended up with a solution to use PHP function time() like this
$reference_number = 'BFF-' . time(); you can change the BFF to something that makes more sense to your business logic.
My unique reference id looks like BFF-1393327176 and the number can be converted from Unix to real time which will give you, Tue, 25 Feb 2014 11:19:36
I hope this helps
If the unique values generated once, you just need to make conditional choice for the rand value and store the value in an array which is going to be the condition -using inarray-:
$amount = 100; // the amount of ids
$previousValues = array();
for ($i = 0; $i < $amount; $i++){
$rand = rand(0,9999);
while (in_array($rand, $previousValues)){
$rand = rand(0, 9999);
}
$previousValues[] = $rand;
$today = date("Ymd");
$unique = $today.$rand;
echo $unique."\n";
}
Checkout this demo.
A possible solution for creating unique "Unique Order Number" is following, I assume that you have orders table and field order_number, then the code is:
$orderNumber = DB::table('orders')->max('order_number') + random_int(10, 100);
If first order number is inserted as "100000000000" that method will give you this numbers:
100000000025
100000000056
100000000089
100000000123
100000000199
100000000232
100000000249
with that approach there is no possibility for non-unique number, but cons is that each number is greater the previous (not 100% random) but that approach is acceptable for most of the cases.

Categories