Prevent duplicate ids from being added to session (array) - php

I got a session which adds ids to an array, the problem is every id gets added even if the id is already present. How can I prevent duplicate id's from being added to the array?
I figured I need to check for the id using in_array but I don't know exactly how to use it correctly.
I send the id of the product to my quote page using this link:
<p><a class="offertelink" href="offerte.php?product='.$productcr[0]['id'].'">Request a quote</a></p>
Then on that page I use the following code:
if(!isset($_SESSION['product'])){
$_SESSION['product'] = array();
}
// CHECK FIRST THAT $_GET['product'] IS SET BEFORE ADDING IT TO SESSION
if( isset($_GET['product'])){
$_SESSION['product'][] = $_GET['product'];
}
$prods = implode(",", $_SESSION['product']);
And finally load all the products with the ids that are inside the array:
if(count($_SESSION['product']) != 0){
// offerte overzicht
$offerte = "SELECT * FROM `snm_content` WHERE `id` in (".$conn->real_escape_string($prods).") AND state = 1";
$offertecon = $conn->query($offerte);
$offertecr = array();
while ($offertecr[] = $offertecon->fetch_array());
}
But now everytime I reload the page, the id is added again, it's not really bad since the products are only loaded once, but still I would like to fix this, because I think a query checking for tons of duplicate ids is not the best way.

Using in_array is simple - you just check if element is in array:
var_dump(in_array($element, $array));
In your case it is:
var_dump(in_array($_GET['product'], $_SESSION['product']));
And the check is:
// i advise you to check product value as `int`.
// Because values as `empty string` or `0` or `false` are considered set
if( 0 < intval($_GET['product']) && !in_array($_GET['product'], $_SESSION['product']) ) {
$_SESSION['product'][] = $_GET['product'];
}
But the more clever solution is to use product id as an array key with some fixed value (1 or true for example):
$_SESSION['product'] = [
'101' => 1,
'102' => 1,
'106' => 1,
];
In this case you don't even need to check if your key exists - if it exists it will be overwritten, if not - will be added:
if( 0 < intval($_GET['product']) ) {
$_SESSION['product'][ $_GET['product'] ] = 1;
}
// but here you need to take array keys instead of values
$prods = implode(",", array_keys($_SESSION['product']));

Option 1
Use in_array() to prevent duplicates:
// CHECK FIRST THAT $_GET['product'] IS SET BEFORE ADDING IT TO SESSION
if( isset($_GET['product'])){
if(!in_array($_GET['product'], $_SESSION['product']){
// product not exists in array
$_SESSION['product'][] = $_GET['product'];
}
}
Option 2 empty array before adding products
//if(!isset($_SESSION['product'])){
$_SESSION['product'] = array();
//}

Related

How to check all values present in the column 'pincode'?

This code only reads the first value present in the column. If the value posted in the html form matches the first value, it inserts into the database. But I want to check all the values in the column and then take the respective actions.
For example, if i give input for 'ppincode' and 'dpincode' as 400001, it accepts. but if i gave 400002, 400003,..... it displays the alert even if those value are present in the database
DATABASE:
pincode <== column_name
400001 <== value
400002
400003
400004
...
also i tried this
$query = "SELECT * FROM pincodes";
$result = mysqli_query($db, $query);
$pincodearray = array();
if (mysqli_num_rows($result) > 0) {
while($row = mysqli_fetch_assoc($result)){
$pincodearray[] = $row;
}
}
If I understand well - you want to compare value from POST request with all retrieved records saved in DB and if it matches - perform action.
If so, I would recommend using for(each) loop. Example:
if( !empty($row){
foreach( $row as $key ){
if($key['pincode'] == $ppincode && $key['pincode'] == $dpincode){
// your action goes here
}
}
}
Additional tip: use prepared statements :)
SELECT count(*) FROM table WHERE ppincode=ppincode AND bpincode=bpincode
if this return 0 then insert or else show alert.

mySql select multiple IDs with possible repeating IDs for shopping cart

I am trying to get the cost of all the items by the IDs and then add them up for a shopping cart. I have two issues:
1.) The users may have more than one item with the same ID. Using the method below mySql will not select the item twice. In the example below I have THREE items with the ID of '01' and TWO items with the ID of '07'. However my select statement will only select each ID once.
2.) The method I am using below adds a comma at the end of the last ID so my statement will not work. I need the comma's in between each item for the select but not on the last one. How can I resolve this issue?
if($_SESSION[InCart])
{
foreach($_SESSION[InCart] as $result)
{
$Items .= $result . ',';
}
}
include('../connect.php');
// EXAMPLE RESULT MAY LOOK LIKE THIS
// echo $Items (would print: 01,09,07,01,01,23,07,)
$sql = "SELECT Cost FROM cartItems WHERE itemNumber IN ('$Items')";
$result = $conn->query($sql);
$Cost = 0;
if ($result->num_rows > 0)
{
// output data of each row
while($row = $result->fetch_assoc()) {
$Cost = $Cost + $row["Cost"];
}
}
else {
echo "0 results";
}
$conn->close();
You should keep track of how many items of each type in your cart.
so in the cart you have now like
$items = [1,1,1,2,6];
you should have them like this
$items = [
'item-1' => 3,
'item-2' => 1,
'item-6' => 1
];
I never use integers for associate keys, if you sort ( or some other array functions ) an array like that it will mess it up by reordering or resetting the numeric keys, [1=>3,2=>1,6=>1] could become [0=>3,1=>1,2=>1] for example. You can make it more readable and protect them by prefixing them with a string like item-, So then you just do something like:
$itemIDs = [];
foreach( $items as $itemID => $Quantity ){
//replace item- with empty, you could also use substr, or even str_replace.
$itemIDs[] = (int)preg_replace('/^item-/', '', $itemID);
}
That will give you a list of ids like you have ( minus the duplicates )
$itemIDs = [1,2,6];
Do your search and in the while loop
while($row = $result->fetch_assoc()) {
//correlate it back to original $items using the key [item-{ID}] to get the quantity
$Cost += ( $row["Cost"] * $items['item-'.$row['ID']] ); //cost + ( item cost * quantity )
}
Multiply the items cost by the quantity in the cart, add that to your sum....
For this bit in your sql:
$sql = "SELECT Cost FROM cartItems WHERE itemNumber IN ('$Items')";
instead do this
$sql = 'SELECT Cost FROM cartItems WHERE itemNumber IN ('.implode(',', $itemIDs) .')';
You wont need to quote them because we cast them to int in the foreach loop. This is a regular expression that matches ^ starts with item-, so it matches the item- and removes it. ( see it in action here https://regex101.com/r/pLqDWw/1 )
(int)preg_replace('/^item-/', '', $itemID);
So that will come out like ( I think, just doing it in my head )
$sql = 'SELECT Cost FROM cartItems WHERE itemNumber IN (1,2,6)';
Which is fine because generally integers don't need to be quoted in MySql. This also has the benefit of sanitizing them to prevent any Sql Injection, because casting them wont allow any alphabet or special characters though.
I changed the " to single quotes ', it just makes it look better when used as a query without variable interpolation "$var" for example.
UPDATE: to add items
$items = isset($_SESSION['items']) ? $_SESSION['items'] : []; //check if items array is saved in the session.
$key = 'item-'.$_POST['itemID'];
if( !isset( $items[$key] ) ){
$items[$key] = $_POST['quantity'];
}else{
$items[$key] += $_POST['quantity'];
}
$_SESSION['items'] = $items;
Assuming $_POST['itemID'] is the items id and $_POST['quantity'] is the number to add. Same goes for subtracting except for that I would add
if( $items[$key] <= 0 ){
unset( $items[$key] ); //remove item from list.
}
You can use a join for this calculation -- because you explicit want duplicates. However, the query is a bit more challenging to generate:
SELECT SUM(cost) as cost
FROM cartItems c JOIN
(SELECT 1 as itemNumber UNION ALL
SELECT 1 UNION ALL
SELECT 2
) i
ON i.itemNumber = c.itemNumber;
Note: You should use aggregation in the query to add all the values together. That is the best way to use SQL for this purpose.

Use of unset and count with arrays

I have a array that contains other arrays with each user's details in. For example:
$_SESSION["ActQueue"] = [["J.Paul", "John", "Paul", "0000-00-00 00:00:00"],["J.Bloggs", "Joe", "Bloggs", "0000-00-00 00:00:00"]]
I have written a bit of code that is mean to turn the "account rank" of the first user in the array to "Cadet" in the database. The code then removes the user from the array and then should either echo data = 1 or the next user in the list depending if they exist. I have done this with the following bit of code, however I have found that when unset deletes the first item it the keys don't shift down 1, so 0 will simply not exist and 1 will still be "J.Bloggs". As a result when the next user is echoed no values are sent. Any suggestions?
<?php
session_start();
require "classes.php";
$TF = new TF_Core ();
$ActQueueAccept = "UPDATE users
SET rank = 'Cadet'
WHERE username = ?";
if ($statement = TF_Core::$MySQLi->DB->prepare($ActQueueAccept)) {
$statement->bind_param('s',$_SESSION["ActQueue"][0][0]);
$statement->execute();
}
unset($_SESSION["ActQueue"][0]);
if(count($_SESSION["ActQueue"] != 0)){
echo json_encode(['Username'=>$_SESSION["ActQueue"][0][0], 'Surname'=>$_SESSION["ActQueue"][0][1],'Forename'=>$_SESSION["ActQueue"][0][2],'Joined'=>$_SESSION["ActQueue"][0][3]]);
}
else{
$data = 1;
echo $data;
}
?>
unset($_SESSION["ActQueue"][0]);
$_SESSION["ActQueue"] = array_values($_SESSION["ActQueue"]);
It seems that unset() does not always reset array keys. The function array_values redefines my array with the correct keys / indexes it.

Where Operator In Laravel

I need to use where operator to check some ids in my table as the following
$subScIDs = SubjectSchedule::where('subject_start_id',Input::get('substID'))
->whereNull('deleted_at')
->select('id')->get();
$subScIDsArray = array() ;
foreach ($subScIDs as $id)
{
$subScIDsArray [] = $id->id ;
}
// here my issue
$subScInStudAttends = StudentAttendees::whereIn('subject_schedule_id',$subScIDsArray)
->select('subject_schedule_id')->get();
if ($subScInStudAttends)
{
return " true " . $subScInStudAttends;
}else{
return "false";
}
My issue in this code
$subScInStudAttends = StudentAttendees::whereIn('subject_schedule_id',$subScIDsArray)
->select('subject_schedule_id')->get();
whereIn working well it fetch any id in $subScIDsArray, but i need to check each id of ids if one id in $subScIDsArray not equal subject_schedule_id' return false ;
How I Can do it ?
Any Suggestions ?
You can check the length of the array that contains the ids against the length of the records returned.
if( count($subScIDsArray) == count($subScInStudAttends) ){
// all IDs in the array have a corresponding record in the database
}
Or better, if your application logic permits it, simply get the count of the records and then compare with the length of the ids array.
$subScInStudAttendsCount = StudentAttendees::whereIn('subject_schedule_id', $subScIDsArray)->count('subject_schedule_id');
if( count($subScIDsArray) == $subScInStudAttendsCount ){
// all IDs in the array have a corresponding record in the database
}
This code assumes the ids in your database are all unique.

PHP SQL Update array

I originally was satisfied with the following in order to update row 1 and row 2 to the same value (status=1)
if ($_POST){
$sql ="UPDATE table SET status = 1,
WHERE id IN (1,2 );";
db()->query($sql);
if(db()->query($sql)){
echo "<b>Good</b>";
}
else{
echo "<b>No Good</b>";
}
}
But now I want to update with different values, ie- row 1 to status 1, row 2 to status 2, and row 3 to status 3.
Off the bat, I know I need to
1. Use an array and loop through it three times.
2. pass in the array value into the $sql
I figure it would be something like this but I am still learning PHP..
$array_id = array(1, 2, 3);
$array_status = array(1, 2, 3);
if ($_POST){
$sql ="UPDATE table SET status = $array_status
WHERE id = $array_id;";
db()->query($sql);
if(db()->query($sql)){
echo "<b>Update Successful</b>";
}
else{
echo "<b>Update Unsuccessful</b>";
}
}
How would I go about making this happen?
You can loop through the arrays using a for loop and exec a query for each one (Radu Vlad answer), or you can build a long query and execute it once, something like this:
if ($_POST){
$sql = ""; // Blank string
$len = count($array_id); // Number of iterations
for ($i = 0; $i < $l; $i++) { // Enter the loop
$sql .= "UPDATE
table
SET
status = {$array_status[$i]}
WHERE id = {$array_id[$i]};"; // Append the query
}
db()->query($sql);
if(db()->query($sql)){
echo "<b>Update Successful</b>";
}
else{
echo "<b>Update Unsuccessful</b>";
}
}
When the val of $i is 0, then $array_id[$i] will print the first element, when $i is 1, $array_id[$i] will print the second element, and so on.
Using .= you append text to a string. By the end of the loop, $sql will be a string with 3 queries ('UPDATE ... SET ...; UPDATE ... SET ...; UPDATE ... SET ...;').
Not sure if it's the best way, though. But you get the idea.
If yow want the status to be equal to the id, do this (single query):
UPDATE table SET status=id WHERE id IN (1,2,3);
Of course you can use some math, like:
UPDATE table SET status=(id+1)*2 WHERE id IN (1,2,3);
You didn't really explain why you need that, so
try1(childish): set status = id
"UPDATE table SET status = id"
It's a bad practice, and only you could understand what those numbers are. Plus if id is auto-increment, status will be auto-increment too, you will have a duplicate column. If status has only 3 values posible, you should not do this.
try2(basic): do 3 updates, or actually, do as many as you need with a for
if ($_POST){
$status = 1;
for ($i = 1; $i <= 3; $i++){
$sql ="UPDATE table
SET status = $status
WHERE id = $i;";
db()->query($sql);
$status++;
}
A better way bacause you have more control over the status. Of course the second try is irrelevant if you have only that 3 values. This one assumes you will change the $status variable inside the for loop, in concordance with the $i (id)
try3(mature): set one or 2 arrays with the concordance between id and status, so that either $arr[$id] will have the value of status and the key will be the id, or $arr1[$i] will have the value of id, and $arr2[$i] will have the value of status
the example will have only one array(also called map, because you map a value based on another value)
if ($_POST){
$status_array = array(1 => 1,2 => 2,3 => 3);
for ($i = 1; $i <= 3; $i++){
$sql ="UPDATE table
SET status = $status_array[$i]
WHERE id = $i;";
db()->query($sql);
}
Also, this works because the array is consistent. If you do not have an consistent array you should either work with 2 arrays, or try a foreach with key->value instead of for
I would suggest you to use the following code:
$theArray = array("1" => "1","2" => "2","3" => "3"); // The scheme is ID => Status
$errorMsg = false; // Our default assumption is that no error occured
foreach($theArray as $key => $value) {
$sql = "UPDATE table SET status =".$value." WHERE id = ".$key;
if(!db() -> query($sql)) { // Execute the query and check whether it failed
$errorMsg = "Query for ID ".$key." failed.";
break; // When the query failed we exit the loop and echo the error message
}
}
if($errorMsg) { // If an error occured (errorMsg is no longer false) we echo it here
echo $errorMsg;
}
Basically you do just create one array $theArray, which contains key => value pairs of the IDs and the statuses you want to give them. Afterwards, you loop through this array, execute the db() -> query() for each key => value pair and check whether it failed or not. If a query failed, you break the loop and output the error message.
Advantages:
Instead of using two arrays ($array_id, $array_status) I do use only one associative array $theArray. The advantage here is that you only have one instead of two arrays and that you can extend the number of rows you'd like to change without changing your code. Just extend the array.
The array $theArray does not need to be in a chronological order and you can give each ID independently of the other IDs a status.
You are executing the db() -> query($sql) in your code two times. This is not very efficient and redundant. Instead you can execute the command only once and immediately check whether it failed or not based on its return value inside the if().
The errorMsg I am creating in the code let you know which query failed so it gives you a more detailed information for debugging.
If you want to update multiple rows (in single query) using the INSERT syntax, you can do this:
REPLACE table(id,status) VALUES(1,1),(2,2),(3,3)
Notice that id must be Primary Key or Unique, otherwise the REPLACE will insert a new row.
Notice also that REPLACE isn't SQL standard, and works only in MySQL.

Categories