I have a question please,
I am making an online store.
It offers a product with an available quantity attribute
Let's imagine a certain product has 1 quantity available only.
2 users are logged in and added this element to cart.
They both at the same time checked out (I am trying to do this by splitting 2 browsers in the screen and pressing at the checkout button simultaneously.)
How can I manage that the product checkout is successful for only one user in this case?
if ($_SERVER["REQUEST_METHOD"] == "POST") {
if(isset($_POST['qty_array'])&&isset($_POST['ids_array'])){
$order_address=$_POST['addressCart'];
$ids_array=$_POST['ids_array']; //this is array of product ids in the cart
$qty_array=$_POST['qty_array']; // this is array of quantities in the cart
$date=date("Y-m-d H:i:s");
$j=0;
$x=0;
foreach($ids_array as $id){
$query = "SELECT available_quantity from products where product_id='$id' AND product_active=1";
$result = mysqli_query($db,$query);
$row = mysqli_fetch_array($result);
$qty1=$qty_array[$j];
if($row['available_quantity']==0 || $qty1>$row['available_quantity']){
$x++;
}
$j++;
}
if($x!=0){
$msg="unable_checkout";
echo $msg;
}
else{
$bool=mysqli_query($db,"INSERT INTO order_table(customer_id,order_date,order_address)
VALUES ('$customerID','$date','$order_address')") or die("".mysqli_error($db));
$order_id=mysqli_insert_id($db);
if($bool){
$k=0;
foreach($ids_array as $id){
$query2 = "SELECT * from products where product_id='$id' AND product_active=1";
$result2 = mysqli_query($db,$query2);
$row2 = mysqli_fetch_array($result2);
$qty_available=$row2['available_quantity'];
$qty=$qty_array[$k];
$unitprice=$row2['product_price'];
$discount=$row2['product_discount'];
if($qty<=$qty_available && isset($_SESSION['cartProds']) && $qty_available!=0 ){
mysqli_query($db,"INSERT INTO order_details(order_id,product_id,unitprice,discount,quantity)
VALUES ('$order_id','$id','$unitprice','$discount','$qty')") or die("".mysqli_error($db));
$newqty=$qty_available-$qty;
mysqli_query($db,"UPDATE products SET available_quantity='$newqty' WHERE product_id='$id'");
}
$k++;
}
}
$msg="checkedout_successfully";
//unset inserted order :
unset($_SESSION['cartProds']);
$_SESSION['nOfProds']=0;
echo $msg;
}
}
I need to stop the submission and to not insert anything when one of the quantities is equal to Zero.
What I am getting is that if 2 users want to checkout 3 same products at the same time (one product is added to order table of user 1 , and the other 2 are added to order table of user2 ..which is wrong , I want in this case to make checkout successful for only one user, and to give a warning alert msg for the second user)
Ajax code:
$(document).ready(function() {
$("#enableAddress").change(function(){
if($("#enableAddress").prop("checked") == true){
$("#addressCart").prop('disabled',false);
}
else{
$("#addressCart").prop('disabled',true);
}
});
$("#checkoutBtn").click(function(){
var ids_array = [];
$('input[name^=checkoutHidden]').each(function(){
ids_array.push($(this).val());
});
var qty_array = [];
$('input[name^=quantity]').each(function(){
qty_array.push($(this).val());
});
var telCart = $("#telCart").val();
var addressCart = $("#addressCart").val();
$.ajax({
type: "POST",
url: "../phpOnly/checkOut.php",
data: { ids_array:ids_array, qty_array:qty_array,addressCart:addressCart},
success: function(msg) {
// alert(msg);
if(msg=="checkedout_successfully"){
// $("#orderMsg").fadeIn(3000);
// $("#cartBody").fadeOut(2000);
// $("#nOfProdsSpan").text('0');
alert(msg);
}
else if(msg=="unable_checkout"){
// window.location.href="#";
// $("#inavailableMsg").fadeIn(1000);
alert(msg);
}
}
});
});
});
Don't forget that I am taking into consideration that the available quantity is only 1 ( which only one user can order it only)
An approach to handle concurency would be to change the logic, and start the process by attempting to update the products table, with a where clause that ensures that the requested quantity is available, like so:
UPDATE products
SET available_quantity = available_quantity - 1
WHERE
product_id = :id
AND product_active = 1
AND available_quantity > 0
You can then check the number of rows affected by the query:
if one row was affected, then it means the that check out did succeed; you can then do the rest of the process (create the order and the order details records)
if no row was affected, then the check out failed; do not create the order
With this technique, you let the database handle the concurrency for you, and you are guaranteed to never sell more product than available.
Related
I have a Table where user can create row with adding input fields dynamically (combination with jquery). I'm successfully able to insert it into the mysql database.
If users want to edit the added already existing fields, I have an edit page where the values are fetched from the mysql DB and populated again into the dynamically creatable table.
Now there are the below probabilities:-
User only makes minor changes on the existing values. In that case
the table has to be UPDATED with the changed values
User Deletes one/multiple row(randomly selected and as per users wish). So when form submitted the php query should only DELETE that perticular row/s in the DB.
User ADDS another row to the previous existing row values, in that case the php query should UPDATE the previous values and INSERT the newly added row values.
The above sequence is not necessarilly restricted the same order. User can perform all the above three function simultaneously at the same time.
Now my problem is(only for the backend) I'm finding a hard time to frame a php & sql query so as to update to the mysql.
my php
if(isset($_POST['submit'])){
$number1 = count($_POST['item']); //
for($i=0; $i<$number1; $i++){
$item = strip_tags(trim($_POST['item'][$i]));
$description = strip_tags(trim($_POST['description'][$i]));
$unitcost = strip_tags(trim($_POST['unitcost'][$i]));
$qty = strip_tags(trim($_POST['qty'][$i])); // Quantity
$sno = strip_tags(trim($_POST['sno'][$i]));// serial number
//QUERY1 if minor updates to above variable then UPDATE (eg, qty value is changed from 3 to 4)
//QUERY2 if row is deleted then DELETE that particular row from db (eg, sno 3 deleted from the table should DELETE corresponding mysql DB values also)
//QUERY3 if row is added then that particular row values should be INSERT (eg, sno 4 is added which is not in the mysql db. So this has to be INSERTED.)
}
}
Pardon me to have asked such question. I'm wasting a whole lot of time with the above queries unable to execute properly. I only require an idea not necessarily the whole code.
Hope all of you out there would advice me some ideas on how this could be implemented. Thanks for the help in advance. Expecting a positive reply.
NB: Just to remind you again, The front end is a Dynamically ADD/DELETE Input Field table
This sounds like a frontend problem. You need to define how you tell the backend whats happening.
<input name="items[$i][name]" />
This will show up as nice array to loop through in php.
foreach($_POST[items] AS $item){
if( $item['delete'] ){
//delete code
}
}else{
//Insert/Update
}
If you want to delete something simply make the field hidden and add a flag to it.
<input type="hidden" name="items[$i][delete]" value="1" />
<input type="hidden" name="items[$i][id]" />
Thank for the reply, appreciate #ckrudelux and #codefather for their intention to help me.
Although their advise didn't help me to structure my query. So I had a long workaround and found out below solution. I'm posting the solution because I couldn't find any article online when it comes to UPDATE/DELETE a dynamically generated input table.
Hope this would be of help to someone.
So what I did basically is that I took all the values into array.
In my dynamically generated add input table code, I added an <input type="hidden" name="sno[]" value="newrow">. So this will be clubbed with the form post. I'm using the normal html post and not ajax.
now my submit.php has ben changed to below
if(isset($_POST['submit'])){
$productid = $_POST['productd'];// No striptag functions
// due to illustration purpose
// First of all, we need to fetch the querying db table.
// This is required in order to compare the existing row values
// with the posted values
$fetchproduct = $link->prepare("SELECT * FROM product WHERE productid=?");
$fetchproduct ->bind_param('s',$productid);
$fetchproduct ->execute();
$fetchresult = $fetchproduct ->get_result();
$serialnumber=array(); // Assigning array to fetch the primary key: Serial Number
while($row = $fetchresult->fetch_assoc()){
$serialnumber[] = $row["sno"];
}
//Newly Inserted Values
//$_POST['sno'] is taken from the dynamic input field defined earlier in this post.
//Basically what we are doing here is we are comparing (the values
//which have been posted from the primary page) and (values present in the db table).
//The difference will give an array of newly inserted table input field values
$insert = array_diff($_POST['sno'],$serialnumber);
//Deleted Values
// This will Difference those values in the db table and values which are
// deleted from the primary dynamic table page
$delete = array_diff($serialnumber,$_POST['sno']);
$countdelete = count($delete); // Counting how many values have been
// lined up for deleting
//Updated Values
// array_intersect will give us the common values present in both the array.
// This means that there is no deletion or insertion to the dynamic table fields.
$intersect = array_intersect($serialnumber, $_POST['sno']);
$update = array_values($intersect);
$countupdate = count($update);
//INSERT ADDED VALUES TO DB
foreach($insert as $key=>$ivalue){
// ID
if(isset($_POST['id'][$key]) && !empty($_POST['id'][$key])) {
$id = strip_tags(trim($_POST['id'][$key]));
}
// ITEM
if(isset($_POST['item'][$key]) && !empty($_POST['item'][$key])) {
$item = strip_tags(trim($_POST['item'][$key]));
}
// DESCRIPTION
if(isset($_POST['description'][$key]) && !empty($_POST['description'][$key])) {
$description = strip_tags(trim($_POST['description'][$key]));
}
// UNITCOST
if(isset($_POST['unitcost'][$key]) && !empty($_POST['unitcost'][$key])) {
$unitcost = strip_tags(trim($_POST['unitcost'][$key]));
}
// QUANTITY
if(isset($_POST['qty'][$key]) && !empty($_POST['qty'][$key])) {
$qty = strip_tags(trim($_POST['qty'][$key]));
}
// AMOUNT
if(isset($_POST['amount'][$key]) && !empty($_POST['amount'][$key])) {
$amount = strip_tags(trim($_POST['amount'][$key]));
}
// INSERT INTO THE DATABASE
$inserttable = $link->prepare("INSERT INTO product (productid, item, description, unitcost, qty, amount) VALUES(?,?,?,?,?,?)");
$inserttable->bind_param('ssssss', $id, $item, $description, $unitcost, $qty, $amount);
$inserttable->execute();
if($inserttable){
header( 'Location:to/your/redirect page.php' ) ; // NOT MANDADTORY, You can put whatever you want
$_SESSION['updatemsg'] = "Success";
}
}
//UPDATE EXISTING VALUES TO DB
for($j=0; $j<$countupdate; $j++){
// ID
if(isset($_POST['id'][$j]) && !empty($_POST['id'][$j])) {
$uid = strip_tags(trim($_POST['id'][$j]));
}
// ITEM
if(isset($_POST['item'][$j]) && !empty($_POST['item'][$j])) {
$uitem = strip_tags(trim($_POST['item'][$j]));
}
// DESCRIPTION
if(isset($_POST['description'][$j]) && !empty($_POST['description'][$j])) {
$udescription = strip_tags(trim($_POST['description'][$j]));
}
// UNITCOST
if(isset($_POST['unitcost'][$j]) && !empty($_POST['unitcost'][$j])) {
$uunitcost = strip_tags(trim($_POST['unitcost'][$j]));
}
// QUANTITY
if(isset($_POST['qty'][$j]) && !empty($_POST['qty'][$j])) {
$uqty = strip_tags(trim($_POST['qty'][$j]));
}
// AMOUNT
if(isset($_POST['amount'][$j]) && !empty($_POST['amount'][$j])) {
$uamount = strip_tags(trim($_POST['amount'][$j]));
}
// UPDATE THE DATABASE
$updatetable = $link->prepare("UPDATE product SET item=?, description=?, unitcost=?, qty=?, amount=? WHERE sno=?");
$updatetable->bind_param('ssssss', $uitem, $udescription, $uunitcost, $uqty, $uamount, $update[$j]);
$updatetable->execute();
if($updatetable){
$_SESSION['updatemsg'] = "Success";
}
}
//DELETE VALUES FROM DB
foreach($delete as $sno){
$deletetable = $link->prepare("DELETE FROM product WHERE sno=?");
$deletetable->bind_param('s', $sno);
$deletetable->execute();
if($deletetable){
$_SESSION['updatemsg'] = "Success";
}
}
}else {
$_SESSION['updatemsg'] = "Error";
}
}
I've been trying to use AJAX and JSON to show the contents of individual items from my database through the following codes below. What I'm trying to achieve is that whenever an individual item is opened or clicked, it will show up its unique content on the next page.
However, succeeding items just show the details of the initial item which has the ID '1'. I have more than 10 items in my DB and I want these to reflect their corresponding data.
//productpage_endpoint.php
require "connection.php";
$id = $_POST['id'];
$sql = "SELECT * FROM items WHERE id = $id";
$result = mysqli_query($conn,$sql);
$result = mysqli_fetch_assoc($result);
echo json_encode($result);
<script type="text/javascript">
$.post('productpage_endpoint.php',**{id: 1}**,
function(data){
var item = JSON.parse(data)
$('input[name=name]').val(item.name)
$('input[name=description]').val(item.description)
$('input[name=price]').val(item.price)
$('#item_image').attr('src',item.image)
}
)
</script>
If you'd like to request all items in the table:
$sql = "SELECT * FROM items";
In JS you'll need to create new elements for all of the values. Otherwise you'll overwrite the existing form values.
$.post('productpage_endpoint.php',
function(data){
for (var item in data) {
$('<input>')
.attr('name', 'name')
.attr('type', 'text')
.val(item.name);
// ...
// Add to your form...
}
}
)
I have a database where it has 10+ records:
Accid | Firstname | Lastname
1. John Marshall
2. Sherlock Holmes
3. Random Dude
...
I'd display this using echo on php but with AJAX... it first loads up 5 users, and when the user has scrolled at the bottom of the page, it will load another 5 on the list (it adds the Offset's value +=5). Here's my display code:
$sql = "SELECT * FROM users ORDER BY lastname DESC LIMIT 5 OFFSET 5";
$result = mysqli_query($connection,$sql);
While($row=mysqli_fetch_assoc) {
echo $row['lastname']." ".$row['firstname']."<br/>";
}
This list could be very long if I have 100 users let's say.
Whenever the user scrolls at the bottom, another 5 users pops up. Now, if I reached the end of the whole records in the USERS database, I'd like to display something like - "End of User List"
How can I achieve this?
Jquery Code
$.ajax({
type: "GET",
url: "getusers.php",
data: {
'offset': 4
},
success: function(data){
$('#displayusers').append(data);
}
});
I'd like to disagree with #PressingOnAlways answer.
You can just send back a different response from PHP and check it in javascript.
$sql = "SELECT * FROM users ORDER BY lastname DESC LIMIT 5 OFFSET 5";
$result = mysqli_query($connection,$sql);
if(mysqli_num_rows($result) == 0){
die("last");
}
While($row=mysqli_fetch_assoc) {
echo $row['lastname']." ".$row['firstname']."<br/>";
}
Now you can just check it in javascript:
if(response == "last"){
mydiv.append('This is the end');
}
Now, I would like to show you my way of doing things, which (imo) is a lot cleaner:
First, your ajax calls
We're going to make sure our data will be in json format automatically from now on:
$.ajax({
type: 'GET',
url: "getusers.php",
cache: false,
data: {'offset': 4},
dataType: "json"
}).done(function(json){
if(json.hasOwnProperty("last"){
//No more results
//do your thang;
return false;
}
if(getLength(json) < 5){
//Smaller then 5, must have hit the last. Do your thang;
return false;
}
//It came here, so it's all good. Go on
$('#displayusers').append(data);
});
Secondly: Your PHP side
It's never a good plan to echo html over AJAX. It's way more efficient (takes up less servertime + sends smaller amounts of data over the internet highway) than doing it in PHP.
$sql = "SELECT * FROM users ORDER BY lastname DESC LIMIT 5 OFFSET 5";
$result = mysqli_query($connection,$sql);
$lastResponse = array("last" => "last");
if(mysqli_num_rows($result) == 0){
//Always send back json or it'll give you an error
die(json_encode($lastResponse));
}
$return = array();
While($row=mysqli_fetch_assoc) {
$return[] = $row['lastname']." ".$row['firstname'];
}
echo json_encode($return);
Third: A js function to check the arrayLength
//Checks the length of a json object or array
//Returns false if length is 0 or unable to check it
function getLength(obj) {
if (typeof obj == 'undefined') {
return false;
}
var l = 0;
if (typeof obj == 'object') {
l = Object.keys(obj).length;
}
else {
l = obj.length;
}
return (l == 0 ? false : l);
}
The best place to implement this feature would be on the JS client side. Since your PHP script has no way of knowing if it is the end of the list or not, you need to do this on the client. The JS code should check if the results returned from your php script is less than 5, if so, the "End of User List" should be printed.
I need to automatically refresh content from a mysql data table every 5 seconds, but showing only one distinct record at a time, going through every record in a endless loop.
I load news.php, that has this js :
<script type="text/javascript">
var auto_refresh = setInterval(function () {
$('#canvas').load('content.php').fadein("medium");}, 5000);
// refresh every 5 seconds
</script>
content.php has the db connection
$query_Recordset5 = "SELECT * FROM news";
$Recordset5 = mysql_query($query_Recordset5, $connection) or die(mysql_error());
$row_Recordset5 = mysql_fetch_assoc($Recordset5);
$totalRows_Recordset5 = mysql_num_rows($Recordset5);
As well as the fields echoed to the page.
I understand that you would have to create a counter and bring back one different record everytime, but I am having a tough time with it.
Thanks
If your table has an auto increment field (say "id"). You start by passing page.php and id of 0, so it will grab the auto increment field greater than 0, and then you pass that fields ID back through jquery. When you send it a second time it will not be included because you will be using the greater than sign.
The if num_rows == 0 checks to see if there are any fields, if none, then it will assume that the auto increment field you sent it is the last one, and then it will run the sql statement with the very first auto increment value.
<?php
// page.php
$id = (int) $_REQUEST['id'];
$sq = "select * from news where id > ".$id." order by id asc limit 0,1";
$qu = $con->query($sq);
if ($qu->num_rows == 0) {
$sq2 = "select * from news order by id asc limit 0,1";
$qu2 = $con->query($s2);
while ($fe = $qu->fetch_assoc()) {
echo $fe['id']."|".$fe['content'];
}
} else {
while ($fe = $qu->fetch_assoc()) {
echo $fe['id']."|".$fe['content'];
}
}
?>
<script>
$(document).ready(function() {
setInterval(function(){ updateNews(); }, 5000);
});
function updateNews() {
var id = 0;
id = $("#hidden-id").val();
$.get("page.php?id=" + id, function(data) {
// I use $.get so that I can split the data that it returns before populating
// the #canvas. This way we can strip off the first part which is the auto
// increment
var ref = data.split('|');
$("#hidden-id").val(ref[0]);
$("#canvas").html(ref[1]);
});
}
</script>
I've a online book store where I sell books. Here I store data's of the cart on session. When two or more books are selected there may not be all the books available. I can do check only fore one book that is available or not. But I can't make it through when two or more books selected for ordering. What I did for one book is:
$result = mysql_query("SELECT id FROM book_table WHERE id IN ($cart)");
while ($row = mysql_fetch_array($result)) {
$q=mysql_num_rows(mysql_query("SELECT available FROM book_table WHERE id='$row[0]'"));
if($q!=0){
//order goes fore processing.
}
else{
//books not available.
$q2=mysql_fetch_array(mysql_query("SELECT name FROM book_table WHERE id='$row[0]'"));
echo "The book: $q2[0] Not Available";
//If there is more than 1 books in the cart and one or two books of them are not in the stock, its showing the order cant be processed(But I want to show which books aren't available).
}
}
Here $cart is the books cart saved on session like 1,2,3,4.
Now I need to show which books aren't available to buy by redirecting with another page.
Can anyone help me out on this?
make a array and put id and availaibilty as key and values pair and check for availaiblity for each id.
$all_available = true;
$orders = array();
$result = mysql_query("SELECT id, available, name FROM book_table WHERE id IN ($cart)");
while ($row = mysql_fetch_assoc($result)) {
if ($row['available')) {
$orders[] = $row['id'];
} else {
$all_available = false;
echo "The book: " . $row['name'] . " is not available.\n"
}
}
if ($all_available) {
// Process $orders
} else {
// Send redirect
}
You can do like below,
$query=mysql_query("SELECT id,available FROM book_table WHERE id IN ($cart) ");
$books_available_num = mysql_num_rows($query);
$books_order_num = count(explode(",",$cart));//i think there should be better way to do this...
if($books_available_num==0){
//no book is available
}elseif($books_available_num==$books_order_num ){
//all books are available
while($fetch=mysql_fetch_array($query)){
//order done successfully.
}
}else{
//some are available some are not.
while($fetch=mysql_fetch_array($query)){
if($fetch['status']=="available"){
//place in order
}else{
//this is not available
}
}
}
//rest of code. I think now you can do yourself.
I show you method and you can improve yourself. Code may contain errors, and you can improve it.
you can use ajax like without redirecting to other page
$.ajax({
url :'yourpage.php',
type :'post',
sucess : function(data){ alert(data)}
})
and your php code need a bit modification
$result = mysql_query("SELECT id FROM book_table WHERE id IN ($cart)");
$error = array();
while ($row = mysql_fetch_array($result)) {
$q=mysql_num_rows(mysql_query("SELECT available FROM book_table WHERE id='$row[0]'"));
if($q!=0){
//order goes fore processing.
}
else{
//books not available.
$q2=mysql_fetch_array(mysql_query("SELECT name FROM book_table WHERE id='$row[0]'"));
$error[] = "The book: $q2[0] Not Available";
//If there is more than 1 books in the cart and one or two books of them are not in the stock, its showing the order cant be processed(But I want to show which books aren't available).
}
if (!empty(error))
{
// print array as you want
}
else
{
echo "order successfully placed"
}
}
see more about jquery ajax
if you want to do that redirecting to other page the out $error in session.
I dont think any other thing can help you
NOTE : avoid using mysql_* as they are deprecated