php import excel file error function str_replace - php

I have the code below, the purpose is to automatically add the product code.
For example, if the product code field is left blank, the default first product will be SP00001.
The next product will be SP00002...
The code still works fine with manually adding products. However, when I use the excel file to import data, I get the above code error.
The place where the product code runs is quite chaotic, only the first product is the code SP00001, then the full SP00002. The next time the code is entered, the codes are repeated a lot without knowing what's wrong. Thanks for your help.
public function cms_save_product($data){
$store_id = $this->auth['store_id'];
$data['user_init'] = $this->auth['id'];
if ($data['prd_code'] == '') {
$code = $this->db
->select('prd_code')
->from('products')
->like('prd_code', 'SP')
->order_by('created desc')
->get()
->row_array();
if(empty($code)){
$data['prd_code'] = 'SP00001';
}else{
$max_code = (int)(str_replace('SP', '', $code['prd_code'])) + 1;
if ($max_code < 10)
$data['prd_code'] = 'SP0000' . ($max_code);
else if ($max_code < 100)
$data['prd_code'] = 'SP000' . ($max_code);
else if ($max_code < 1000)
$data['prd_code'] = 'SP00' . ($max_code);
else if ($max_code < 10000)
$data['prd_code'] = 'SP0' . ($max_code);
else if ($max_code < 100000)
$data['prd_code'] = 'SP' . ($max_code);
}
}
$this->db->insert('products', $data);
}

It looks like you are using the record create date for ordering when looking for the greatest product code. If you are inserting many records in a loop while importing from a spreadsheet, and using something like datetime for your time format, this will cause your routine to generate the same code repeatedly until the next second ticks by. You should use something like:
SELECT MAX(prd_code) FROM products WHERE prd_code LIKE 'SP%'
for your query. This will ensure that you are always incrementing the highest product code.
You also have a problem where there is a maximum of 99999 product codes, which may be too low.
For the product code formatting, your logic can be greatly simplified by using str_pad.
This will completely replace empty codes with SP00001, and handle formatting the code with the correct number of zeroes in order to match the desired length.
$defaultCode = 'SP';
if (empty($code))
{
$data['prd_code'] = $defaultCode;
}
else
{
// Remove the SP prefix from the product code and cast to an int
$numCode = (int)(str_replace('SP', '', $code['prd_code']));
// Increment code
$numCode++;
/*
* Set the pad length to either the size of the default code, or the
* length of the stored product code plus 2 (for "SP" prefix), whichever is larger.
* This ensures that the codes always begin with SP even if they are longer than expected.
*/
$padLength = max(strlen($defaultCode), strlen($numCode) + 2);
// Format the product code using the default code as a left pad
$data['prd_code'] = str_pad($numCode, $padLength, $defaultCode, STR_PAD_LEFT);
}

Related

Sums data from an array that has the same id

I have a query about this project that I am doing, I make a query to my two tables and the data that I call in this case is a quantity number for both, the data displayed is the one that has the same id for both tables.
The problem occurs when I pass two identifiers and to those two identifiers I want to add their current amount with the amount obtained from the other table
In general, what I want to do is add the amounts obtained, this is my code that I am working with, I would really appreciate if you can help me solve it or guide me.
$id_servis = [1077,1078];
$sum_quantity_add = Servis_tareas::where('servis_id',$id_servis)->get();
foreach($sum_quantity_add as $sum_add){
$quantity_two[] = $sum_add->quantity;
}
$quantity_actual = Servis::wherein('id',$id_servis)->get();
foreach($quantity_actual as $quantity_act){
$quantity_one[] = $quantity_act->quantity_final;
}
dd($id_servicios,$quantity_one, $quantity_two);
//ERROR
$total[] = $quantity_one + $quantity_two;
//ERROR
if(is_numeric($total) < 0 ){
Servis::wherein('id',$id_servis)->update(['quantity_final' => 0]);
}else{
Servis::wherein('id',$id_servis)->update(['quantity_final' => $total]);
}
In MySql/SQL there is SUM query which handles the addition and they are called Aggregation Functions, and in Laravel there is a Eloquent equivalent of these Laravel Aggregates, using these methods you will be able to count, max, min, avg on the query end rather than in the PHP end.
So, your code will look like
$id_servis = [1077, 1078];
$sum_quantity_add = Servis_tareas::where('servis_id', $id_servis)->SUM('quantity');
$quantity_actual = Servis::wherein('id', $id_servis)->SUM('quantity_final');
$total = $sum_quantity_add + $quantity_actual;
What you are trying is treating array as numeric value and adding it, which is wrong, + operator behaves totally different while you are using with array, it merges the two array, it is different than array_merge too, so i recommend giving this answer a read + operator for array in PHP
UPDATED:
I still don't understand if you want to replace with the SUM from Servis_tareas in the Servis Table or sum the each others quantity and save it, Code below sum the data from both table and save it.
$id_servis = [1077, 1078];
$servisTareas = Servis_tareas::selectRaw("SUM(`quantity`) as total, `servis_id` ")
->where('servis_id', $id_servis)
->groupBy('servis_id')
->having('total', '>', 0)
->get();
$foundId = [];
$servisTotal = Servis::query()->whereIn('id', $id_servis)->pluck('quantity_final', 'id')->toArray();
foreach ($servisTareas as $servisTarea) {
$foundId[] = $servisTarea->servis_id;
$total = $servisTarea->total + ($servisTotal[$servisTarea->servis_id] ?? 0)
Servis::where('id', $servisTarea->servis_id)->update(['quantity' => $total]);
}
if (!empty($foundId)) {
Servis::whereNotIn('id', $foundId)->update(['quantity' => 0]);
}

PHP / MySQLI won't update properly

PHP / MySQLI
$query = $conn->query(
"SELECT
cart.cart_id,
cart.user_ip,
cart.cart_amount,
cart.fk_product_id,
products.product_id,
products.prod_amount
FROM
cart
INNER JOIN
products
ON
cart.fk_product_id = products.product_id
WHERE
fk_product_id = '{$productID}' AND user_ip = '{$ip}'
");
$item = $query->fetch_assoc():
$FKproductID = $item['fk_product_id'];
$FKproductID = iSQLsecure($objConnection, $FKproductID);
$FKproductID = trim($FKproductID);
$CartAmount = $item['cart_amount'];
$CartAmount = iSQLsecure($objConnection, $CartAmount);
$CartAmount = trim($CartAmount);
$ProductAmount = $item['prod_amount'];
$ProductAmount = iSQLsecure($objConnection, $ProductAmount);
$ProductAmount = trim($ProductAmount);
$one = 1;
$add_amount = $CartAmount + $one;
$remove_amount = $ProductAmount - $one;
if($FKproductID == $productsID) {
$update_cart_item = $objConnection->query("UPDATE cart SET cart_amount = '{$add_amount}' WHERE fk_product_id = '{$productID}' AND user_ip = '{$ip}'");
$update_product_amount = $objConnection->query("UPDATE products SET prod_amount = '{$remove_amount}' WHERE product_id = '{$productID}'");
} else {
$add_item = $objConnection->query("INSERT INTO cart (user_ip, add_amount, fk_product_id) VALUES ('{$ip}', '{$add_amount}', '{$productID}')");
$update_product_amount = $objConnection->query("UPDATE products SET prod_amount = '{$remove_amount}' WHERE product_id = '{$productID}'");
}
$objConnection->close();
My Problem
$update_product_amount = $objConnection->query("UPDATE products SET prod_amount = '{$remove_ProductAmount}' WHERE product_id = '{$productID}'");
I use this two places if($FKproductID == $productsID) { /*HERE1*/ } else { /*AND HERE2*/}
For some reason it works in "HERE1" but not in "HERE2"?
If item is not in cart
It will insert it into my "cart" database and update "products" amount value. It is supposed to remove 1 from the current product amount (10 becomes 9). Instead it turns 10 into -1.
If item is in cart
It updates perfectly and turns 10 into 9. The code is the exact same but gives two different results?
I'll assume the above code isn't complete, since some variable name is inconsistent ($remove_amount vs $remove_ProductAmount) and yet your code run fine on some case.
For the queries, why don't you just subtract the amount on update query? Something like
UPDATE table SET field = field - 1 WHERE x = y
Even if the number 1 is dynamic, it's safer to generate the number on variables then cast it to integer. On worst case, it would be converted to zero (which can be easily added on your if() as additional validation).
I also recommend using debugger. Something like Kint or PsySH would suffice if you don't want to trouble yourself with setting up XDebug.
I think the issue may be with your INNER JOIN. From what I can tell, if the item isn't in your cart, then the cart.fk_product_id won't exist, and therefore the query will return an empty object.
If you have error display turned off (likely in the php.ini with display_errors = Off), non-existant array keys will be treated as null during equations.
When it comes time to do the equations, php will convert null to integer(0) which results in 0 - 1 = -1 if it fails the if statement.
Have you tried to output the returned object of the query? You can do this by using:
echo "<pre>"; print_r($item); echo "</pre>";
(the <pre> tag makes it a bit more readable).
Also, check the status of your httpd/apache error log if you have log_errors turned on.

How to generate voucher code, check the DB if it's unique, generate new one if not

I'm having a loop issue in my script. I've spent a lot of time trying to fix it but I still don't know how to fix the problem. I need your help and suggestions regarding this.
My goal is to create a voucher code generator script where the user enters the number of voucher codes to be generated.
Then, the script will generate the required number of vouchers in the database table, and each voucher code will be checked if it is unique - if not, a new voucher code will be generated and the script will proceed until all vouchers are saved.
The problem is that if voucher already exists in the DB, a new one needs to be generated. This newly generated voucher code needs to be checked again if it's already in the DB, if it's unique it will be saved to the DB and if not, the process will go on again. This is where the loop problem lies. I hope you get what i mean.
By the way, the voucher code is in this format: XXXX-XXXX-XXXX (uppercase letters only)
Here's the current codes that I have:
include 'conn.php';
function WriteCSV($flname,$values) {
$Filename = "./vouchers/$flname.csv";
$fh = fopen($Filename, 'a') or die("can't open file");
$filecontent = $values;
$filecontent .= PHP_EOL;
fwrite($fh,$filecontent);
fclose($fh);
}
function generateCode(){
$chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$res = "";
for ($i = 0; $i < 4; $i++) {
$res .= $chars[mt_rand(0, strlen($chars)-1)];
}
return $res;
}
function generateVCode(){
$c1 = generateCode();
$c2 = generateCode();
$c3 = generateCode();
$voucher = "$c1-$c2-$c3";
return $voucher;
}
function searchDB($con, $voucher){
$rs = mysqli_query($con,"SELECT count(*) AS cnt FROM vouchers WHERE vouchercode = '$voucher'");
$row = mysqli_fetch_assoc($rs);
$cnt = $row['cnt'];
if($cnt > 0){
return '1';
} else {
return '0';
}
}
function checkVoucher($con, $voucher, $vsource, $expiry, $today, $vnum, $vprice){
$dbres = searchDB($con, $voucher);
if($dbres == '1'){ //voucher found in db
$val = '0';
$voucher = generateVCode(); //generate a new voucher
checkVoucher($con, $voucher, $vsource, $expiry, $today, $vnum, $vprice); //repeat the process
} else { // voucher is unique
mysqli_query($con, "INSERT INTO vouchers (vouchercode, source, price, expires, generated) VALUES ('$voucher', '$vsource', '$vprice', '$expiry', '$today')");
$flname = "$vsource - ".date('d M Y')." ($vnum vouchers)";
WriteCSV($flname,$voucher);
$val = '1';
}
return $val;
}
$vnum = $_POST['vouchernum'];
$vsource = $_POST['source'];
$vprice = $_POST['amt'];
$expdate = $_POST['expdate'];
$expiry = $_POST['voucherexpiry'];
$today = date('Y-m-d');
$expconv = date('Y-m-d',strtotime("$expiry"));
$expfive = date('Y-m-d',strtotime("$expiry +5 years"));
for ($x = 1; $x <= $vnum; $x++) {
$vouchercode = generateVCode();
if($expdate == "no"){
$expiry = $expfive;
} else {
$expiry = $expconv;
}
do {
$result = checkVoucher($con, $vouchercode, $vsource, $expiry, $today, $vnum, $vprice);
} while ($result != '1');
header("location: index.php?s=1");
}
By the way, if you have suggestions on how to generate the voucher codes easier, please feel free to share.
I'm thinking the issue/problem here is on either the do-while statement or the checkVoucher() function.
I'd really appreciate you help and suggestions. Thanks.
I would go completely easier. Set the voucher column in your table to unique. Generate a code PHP side, do your insert, in the error callback function call to generate a new code.
Basically, this will self loop until inserted. Then in your success callback add it to your display. All of this is wrapped in a while loop. Once you get your 5, break the loop.
As far as generating a random string with minimal chance of a repeat, check this thread: PHP random string generator
I would generate the full length string and then just add your hyphens.
Using this approach to generate random unique data, the amount of processing required increases proportionally as more and more codes are generated.
What I would do instead is:
Generate a whole bunch of values (lets say a few thousand) values sequentially and store them in a redis/SQL database
Use a random number to index that record in the database, and remove the record from the table once it has been used
This reduces the processing required greatly, and also gives you a pre determined pool of voucher codes which could be useful for other purposes in your application
Mysql unique constraint may be the solution you are looking for.it ensures a value is always unique. It is like primary key. but unlike primary key a table can have multiple unique values.
Here is the link to w3school explaining this
www.w3schools.com/sql/sql_unique.asp
The best part is it will genrerate a Duplicate Entry error when adding a duplicate entry. so you can use it to add data to csv . add it only when you have no error.
But make sure the unique value is not null.

PHP while loop of mysql queries sometimes returns an empty set randomly (they're not empty, but the result is empty)

I am writing a report on data based on new customers for each given month, starting from the earliest month an order was present all the way to the last month that any orders are present (I realize the current code will stop on any month that doesn't have new customers, and will fix later...)
Some background-- I'm using the Flourish Framework (www.flourishlib.com).. The first month/year is set correctly because I have error log'd it out. The first month with orders is 4/2013.
The problem is that for some reason, MySQL randomly returns an empty result at some point that is completely random. I have run the query for that month/year that it returns an empty result for in a MySQL client and it is not an empty result. The script itself proves this to be the case as where it returns the empty result is random and it will go further than it did before sometimes showing the correct information.
I have tried sleeping in between queries, as I originally thought maybe it was throttling or something, no go. Still the same exact behavior. I have tried using retries (when it encounters a count of 0 it will retry up to X times) and EVERY TIME it's empty, which means it cannot be one of those "sometimes it craps out, try again" type of scenarios.
Here is the code as it is now:
function newClients($month, $year) {
$db = fORMDatabase::retrieve();
$noobs = $db->query("
SELECT
id,
email,
(
SELECT completed
FROM orders
WHERE client_id = clients.id
ORDER BY completed ASC
LIMIT 1
) as first_order
FROM clients
HAVING first_order IS NOT NULL
AND MONTH(first_order) = '$month'
AND YEAR(first_order) = '$year'
AND email NOT LIKE '*#********.com'
AND email NOT LIKE '%#********.com'
AND email NOT LIKE '%#********.com'
AND email NOT LIKE '%#********.com'
AND email NOT LIKE '%#********.com'
AND email NOT LIKE '%#********.org'
AND email != '********#gmail.com'
AND email != '********#********.net'
")->fetchAllRows();
return $noobs;
}
$currentMonth = $theFirst['month'];
$currentYear = $theFirst['year'];
$retries = 0;
$noobs = newClients($currentMonth, $currentYear);
while (count($noobs) > 0 || $retries < 3) {
if (count($noobs) == 0) {
error_log('retry #' . ($retries + 1) . '...');
$retries++;
$noobs = newClients($currentMonth, $currentYear);
error_log('count: ' . count($noobs));
sleep(5);
continue;
}
error_log("loop $currentMonth / $currentYear: " . count($noobs));
if ($currentMonth >= 12) {
$currentYear++;
$currentMonth = 1;
} else {
$currentMonth++;
}
sleep(1);
$noobs = newClients($currentMonth, $currentYear);
error_log('count: ' . count($noobs));
}
Couple additional things.. I censored the email addresses for obvious reasons, and I did look at the actual returned data in the MySQL client, it is correct, and I also did vardump the actual array returned and it is indeed empty. (in case you're wondering that maybe count is counting incorrectly or who knows.. I thought maybe it was a countable object/non-array issue or quirk or something)
There may be some confusion as to the retries etc. as that has nothing to do with my desired outcome and were only attempts to solve the issue, here is the original code:
$noobs = newClients($currentMonth, $currentYear);
while (count($noobs) > 0) {
error_log("loop $currentMonth / $currentYear: " . count($noobs));
if ($currentMonth >= 12) {
$currentYear++;
$currentMonth = 1;
} else {
$currentMonth++;
}
$noobs = newClients($currentMonth, $currentYear);
error_log('count: ' . count($noobs));
}
sorry this is probably not really an answer but too big for comments.
i'm not confident this error is in PHP or flakiness with the db connection
can you modify your retry to print out the query and run it in your mysql client by hand ?
maybe you have weird inputs ?
try adding a null check to this
SELECT completed
FROM orders
WHERE client_id = clients.id
AND completed IS NOT NULL
ORDER BY completed ASC
LIMIT 1
i suspect you have your db set to NULLs first and they float to the top of your ordering

php - calculate price multiplied by quantity for several items to get individual totals and a grand total

I have a form that has 7 different items. The user will be able to input quantity (unlimited) and the price will be set for each item (let's say for example, item 1 is $18, and item 2 is $20, etc.). What I have done with another form that's almost identical is this:
if(!empty($_POST[qty_item_1])) {
$total_1 = ($_POST[qty_item_1] * 18);
} else {
$total_1 = "0";
}
if(!empty($_POST[qty_item_2])) {
$total_2 = ($_POST[qty_item_2] * 20);
} else {
$total_2 = "0";
}
I would have a code block like those for each item. It seems to work fine but I feel like this is probably the hard way to do it but I'm having trouble figuring out what else I might do. Any suggestions?
Given your field names, you could do something like:
$totals = array();
for ($i = 1; $i <= 7; $i++) {
$total[$i] = isset($_POST["qty_item_{$i}"]) ? intval($_POST["qty_item_{$i}"]) : 0;
}
The other option is to simply name your fields qty_item[]. When PHP parses the submitted data, it'll convert all those qty_item fields into an array for you. You'd still need to post-process to make sure that they contain valid numbers and whatnot, thoguh.

Categories