PHP skip duplicates - php

I have serious question about importing data from CSV to Database.
Import script:
if (file_exists('temp.csv')) {
$i=0;
require "connection.php";
$handle = fopen("temp.csv", "r");
try {
$import= $db->prepare("INSERT INTO adherence(
dateandtime,
lastname,
firstname,
paidtime,
approvedtime,
notadhering) VALUES(
?,?,?,?,?,?)");
$i = 0;
while (($data = fgetcsv($handle, 1000, ",", "'")) !== FALSE) {
if($i > 0) {
$data = str_replace('"', '', $data);
$myDate = date("Y/m/d",strtotime(str_replace('/','-',$data[0])));
$import->bindParam(1, $myDate, PDO::PARAM_STR);
$import->bindParam(2, $data[1], PDO::PARAM_STR);
$import->bindParam(3, $data[2], PDO::PARAM_STR);
$import->bindParam(4, $data[3], PDO::PARAM_STR);
$import->bindParam(5, $data[4], PDO::PARAM_STR);
$import->bindParam(6, $data[5], PDO::PARAM_STR);
$import->execute();
}
$i++;
}
fclose($handle);
Problem is, I need some sort of conditional logic to check, if row allready exist in database before importing, and skip it - if it exist. How to handle this kind of thing?

Basically you have two different ways to approach it.
1. via the rdbms:
Use an unique index in your table. Once you insert a duplicate,
you'll encounter an error, which can be properly displayed/logged/whatever.
2. via application logic:
Search for your item before inserting with a proper SELECT statement.. If
you find a match, don't insert it.
Example:
$sth = $db->prepare("SELECT yourfields FROM yourtable WHERE yourcondition = :cond");
$sth->bindParam(':cond',$yourvariable, PDO::PARAM_STR);
$sth->execute();
if ($sth->rowCount() > 0) {
// results - don't insert
} else {
// place your insert terms here
}
In most conditions, coders will implement the first way, since it reduces traffic between application and RDBMS and makes your data model more robust. If this is any issue, try the second way.

Related

A problem to use function for get count(*) in pdo [duplicate]

I am having trouble getting bindParam to work inside of a foreach loop. If I use bindParam outside of a loop or hardcode the values into the sql query everything works perfectly. According to this page it is suggested to use bindValue instead. However, when I use bindValue it says that the three variables used inside the bindValue are undefined. Which obviously they are at this point. What am I doing wrong?
<?php
$found_update = false;
$installed_groups = array(
array(
"group_id" => 14,
"version" => "1.0.7"
)
);
$sql = "select id from testing_set where group_id = :GROUP_ID
and (
substring_index(substring_index(version, '.', 2), '.', -1) > :INSTALLED_VERSION_NUM_1 OR
substring_index(substring_index(version, '.', 3), '.', -1) > :INSTALLED_VERSION_NUM_2
)
order by created desc limit 1";
try {
$dbh = new PDO("mysql:host=localhost; dbname=".DBNAME, DBUSER, DBPWD);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $dbh->prepare($sql);
$stmt->bindParam(":GROUP_ID", $installed_group['group_id'], PDO::PARAM_INT);
$stmt->bindParam(":INSTALLED_VERSION_NUM_1", $installed_version_parts[1], PDO::PARAM_INT);
$stmt->bindParam(":INSTALLED_VERSION_NUM_2", $installed_version_parts[2], PDO::PARAM_INT);
foreach ($installed_groups as $installed_group){
$installed_version_parts = explode('.', $installed_group['version']);
$stmt->execute();
$data = $stmt->fetch(PDO::FETCH_ASSOC);
if (!empty($data)){
$found_update = true;
break;
}
}
echo "Found: $found_update\n";
}
catch(PDOException $e) {
http_response_code(404);
die();
}
My expected results are for it to display "Found: 1" to the terminal. The way it is now it has a value of false when it should be true.
Solution:
It turns out there were two issues going on here. I have followed IncredibleHat's answer by using basic variables rather than an array in my bindParam. This helped solve the first problem, but the other problem was that I needed to typecast some of data to an int:
$pt1 = (int)$installed_version_parts[1];
I had assumed that PDO::PARAM_INT was doing that for me, but it was not.
Trying to bindParam to an array element like $array['key'] causes a few issues because its bound as reference, but its not. Its, just not done that way.
So three ways:
$stmt = $dbh->prepare($sql);
// bind to variables that can be a reference
$stmt->bindParam(":GROUP_ID", $id, PDO::PARAM_INT);
$stmt->bindParam(":INSTALLED_VERSION_NUM_1", $pt1, PDO::PARAM_INT);
$stmt->bindParam(":INSTALLED_VERSION_NUM_2", $pt2, PDO::PARAM_INT);
foreach ($installed_groups as $installed_group){
$installed_version_parts = explode('.', $installed_group['version']);
// assign the referenced vars their new value before execute
$id = $installed_group['group_id'];
$pt1 = $installed_version_parts[1];
$pt2 = $installed_version_parts[2];
$stmt->execute();
}
Or: (less efficient)
$stmt = $dbh->prepare($sql);
foreach ($installed_groups as $installed_group){
$installed_version_parts = explode('.', $installed_group['version']);
// use bindValue (not bindParam) INSIDE the loop
// bindValue doesn't set them by reference, so any value expression works
$stmt->bindValue(":GROUP_ID", $installed_group['group_id'], PDO::PARAM_INT);
$stmt->bindValue(":INSTALLED_VERSION_NUM_1", $installed_version_parts[1], PDO::PARAM_INT);
$stmt->bindValue(":INSTALLED_VERSION_NUM_2", $installed_version_parts[2], PDO::PARAM_INT);
$stmt->execute();
}
Or:
$stmt = $dbh->prepare($sql);
foreach ($installed_groups as $installed_group){
$installed_version_parts = explode('.', $installed_group['version']);
// pass them on execute directly
$stmt->execute(array(':GROUP_ID'=>$installed_group['group_id'],
':INSTALLED_VERSION_NUM_1'=>$installed_version_parts[1],
':INSTALLED_VERSION_NUM_2'=>$installed_version_parts[2]));
}

PDO bindParam not working in loop

I am having trouble getting bindParam to work inside of a foreach loop. If I use bindParam outside of a loop or hardcode the values into the sql query everything works perfectly. According to this page it is suggested to use bindValue instead. However, when I use bindValue it says that the three variables used inside the bindValue are undefined. Which obviously they are at this point. What am I doing wrong?
<?php
$found_update = false;
$installed_groups = array(
array(
"group_id" => 14,
"version" => "1.0.7"
)
);
$sql = "select id from testing_set where group_id = :GROUP_ID
and (
substring_index(substring_index(version, '.', 2), '.', -1) > :INSTALLED_VERSION_NUM_1 OR
substring_index(substring_index(version, '.', 3), '.', -1) > :INSTALLED_VERSION_NUM_2
)
order by created desc limit 1";
try {
$dbh = new PDO("mysql:host=localhost; dbname=".DBNAME, DBUSER, DBPWD);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $dbh->prepare($sql);
$stmt->bindParam(":GROUP_ID", $installed_group['group_id'], PDO::PARAM_INT);
$stmt->bindParam(":INSTALLED_VERSION_NUM_1", $installed_version_parts[1], PDO::PARAM_INT);
$stmt->bindParam(":INSTALLED_VERSION_NUM_2", $installed_version_parts[2], PDO::PARAM_INT);
foreach ($installed_groups as $installed_group){
$installed_version_parts = explode('.', $installed_group['version']);
$stmt->execute();
$data = $stmt->fetch(PDO::FETCH_ASSOC);
if (!empty($data)){
$found_update = true;
break;
}
}
echo "Found: $found_update\n";
}
catch(PDOException $e) {
http_response_code(404);
die();
}
My expected results are for it to display "Found: 1" to the terminal. The way it is now it has a value of false when it should be true.
Solution:
It turns out there were two issues going on here. I have followed IncredibleHat's answer by using basic variables rather than an array in my bindParam. This helped solve the first problem, but the other problem was that I needed to typecast some of data to an int:
$pt1 = (int)$installed_version_parts[1];
I had assumed that PDO::PARAM_INT was doing that for me, but it was not.
Trying to bindParam to an array element like $array['key'] causes a few issues because its bound as reference, but its not. Its, just not done that way.
So three ways:
$stmt = $dbh->prepare($sql);
// bind to variables that can be a reference
$stmt->bindParam(":GROUP_ID", $id, PDO::PARAM_INT);
$stmt->bindParam(":INSTALLED_VERSION_NUM_1", $pt1, PDO::PARAM_INT);
$stmt->bindParam(":INSTALLED_VERSION_NUM_2", $pt2, PDO::PARAM_INT);
foreach ($installed_groups as $installed_group){
$installed_version_parts = explode('.', $installed_group['version']);
// assign the referenced vars their new value before execute
$id = $installed_group['group_id'];
$pt1 = $installed_version_parts[1];
$pt2 = $installed_version_parts[2];
$stmt->execute();
}
Or: (less efficient)
$stmt = $dbh->prepare($sql);
foreach ($installed_groups as $installed_group){
$installed_version_parts = explode('.', $installed_group['version']);
// use bindValue (not bindParam) INSIDE the loop
// bindValue doesn't set them by reference, so any value expression works
$stmt->bindValue(":GROUP_ID", $installed_group['group_id'], PDO::PARAM_INT);
$stmt->bindValue(":INSTALLED_VERSION_NUM_1", $installed_version_parts[1], PDO::PARAM_INT);
$stmt->bindValue(":INSTALLED_VERSION_NUM_2", $installed_version_parts[2], PDO::PARAM_INT);
$stmt->execute();
}
Or:
$stmt = $dbh->prepare($sql);
foreach ($installed_groups as $installed_group){
$installed_version_parts = explode('.', $installed_group['version']);
// pass them on execute directly
$stmt->execute(array(':GROUP_ID'=>$installed_group['group_id'],
':INSTALLED_VERSION_NUM_1'=>$installed_version_parts[1],
':INSTALLED_VERSION_NUM_2'=>$installed_version_parts[2]));
}

Redundant binding parameters on a PDO Insert process

FYI: this file is my very first touch with PDO.
I have converted a mysqli PHP file info a PDO PHP file, it works fine. File's goal is: if user does not pass any value on keys ($ca_key1 - $ca_key3) just insert data on DB. If keys are passed and do not exist on DB, insert data on DB. If they do exist, echo an error.
I knew PDO could seem redundant, but in this case where I use same parameters up to 3 times on the same file, I ask: is there any way of binding parameter just one time and use it on the 3 executions? For example, ca_key1 could be just binded once and used on the 3 executions?
If you find any error/mistake on the file apart from this, I would appreciate if you mention me. I'd like to adapt good habits on PDO from the begining.
<?php
session_start();
include("../conexionbbdd.php");
if($_SESSION['estado'] == 'activo'){
if (isset($_POST['ca_name'])&&isset($_POST['ca_content'])&&isset($_POST['ca_img'])&&isset($_POST['ca_key1'])&&isset($_POST['ca_key2'])&&isset($_POST['ca_key3'])){
//CHECK IF USER PASSED VALUES ON KEYS
$ca_key1=$_POST['ca_key1'];
$ca_key2=$_POST['ca_key2'];
$ca_key3=$_POST['ca_key3'];
//IF PASSED, CHECK IF VALUES EXIST ON DB
if ($ca_key1!=="" || $ca_key2!=="" || $ca_key3!==""){
$selectKeys= "SELECT ca_key1,ca_key2,ca_key3 FROM ws_campaigns WHERE ca_fk_us_id = :us_id AND ("
. " (ca_key1!='' AND ca_key1 = :ca_key1) OR (ca_key2!='' AND ca_key2 = :ca_key1) OR (ca_key3!='' AND ca_key3 = :ca_key1) "
. "OR (ca_key1!='' AND ca_key1 = :ca_key2) OR (ca_key2!='' AND ca_key2 = :ca_key2) OR (ca_key3!='' AND ca_key3 = :ca_key2)"
. "OR (ca_key1!='' AND ca_key1 = :ca_key3) OR (ca_key2!='' AND ca_key2 = :ca_key3) OR (ca_key3!='' AND ca_key3 = :ca_key3))";
$statementKeys = $pdo->prepare($selectKeys);
$statementKeys->bindParam(':us_id', $_SESSION['id'], PDO::PARAM_INT);
$statementKeys->bindParam(':ca_key1', $_POST['ca_key1'], PDO::PARAM_STR);
$statementKeys->bindParam(':ca_key2', $_POST['ca_key2'], PDO::PARAM_STR);
$statementKeys->bindParam(':ca_key3', $_POST['ca_key3'], PDO::PARAM_STR);
$statementKeys->execute();
$cuenta = $statementKeys->rowCount();
//IF NOT EXIST, INSERT DATA
if ($cuenta === 0){
$insertCampaign = "INSERT INTO ws_campaigns(ca_id,ca_name, ca_content,ca_fk_us_id,ca_img,ca_prefix,ca_key1,ca_key2,ca_key3
)VALUES('',:ca_name,:ca_content,:us_id,:ca_img,'34',:ca_key1,:ca_key2,:ca_key3)";
$statementInsertCampaign = $pdo->prepare($insertCampaign);
$statementInsertCampaign->bindParam(':us_id', $_SESSION['id'], PDO::PARAM_INT);
$statementInsertCampaign->bindParam(':ca_name', $_POST['ca_name'], PDO::PARAM_STR);
$statementInsertCampaign->bindParam(':ca_content', $_POST['ca_content'], PDO::PARAM_STR);
$statementInsertCampaign->bindParam(':ca_img', $_POST['ca_img'], PDO::PARAM_STR);
$statementInsertCampaign->bindParam(':ca_key1', $_POST['ca_key1'], PDO::PARAM_STR);
$statementInsertCampaign->bindParam(':ca_key2', $_POST['ca_key2'], PDO::PARAM_STR);
$statementInsertCampaign->bindParam(':ca_key3', $_POST['ca_key3'], PDO::PARAM_STR);
$statementInsertCampaign->execute();
$newId = $pdo->lastInsertId();
echo $newId;
}
else{
echo "No se ha creado la campaña. <br>Alguna de las palabras clave utilizadas ya están presentes en una campaña anterior.";
}
}else{
//IF NO VALUES PASSED, INSERT DATA
$insertCampaign = "INSERT INTO ws_campaigns(ca_id,ca_name, ca_content,ca_fk_us_id,ca_img,ca_prefix,ca_key1,ca_key2,ca_key3
)VALUES('',:ca_name,:ca_content,:us_id,:ca_img,'34',:ca_key1,:ca_key2,:ca_key3)";
$statementInsertCampaign = $pdo->prepare($insertCampaign);
$statementInsertCampaign->bindParam(':us_id', $_SESSION['id'], PDO::PARAM_INT);
$statementInsertCampaign->bindParam(':ca_name', $_POST['ca_name'], PDO::PARAM_STR);
$statementInsertCampaign->bindParam(':ca_content', $_POST['ca_content'], PDO::PARAM_STR);
$statementInsertCampaign->bindParam(':ca_img', $_POST['ca_img'], PDO::PARAM_STR);
$statementInsertCampaign->bindParam(':ca_key1', $_POST['ca_key1'], PDO::PARAM_STR);
$statementInsertCampaign->bindParam(':ca_key2', $_POST['ca_key2'], PDO::PARAM_STR);
$statementInsertCampaign->bindParam(':ca_key3', $_POST['ca_key3'], PDO::PARAM_STR);
$statementInsertCampaign->execute();
$newId = $pdo->lastInsertId();
echo $newId;
}
}else{
header('location:../paneles/campana.php?msg=nodata');
}
}else{
header('location:../login.php?msg=nopermission');
}
?>
Actually, you don't have to bind [explicitly] at all.
PDO is a great step further compared to mysqli, and this is one of it benefits: you can create an array of variables, and pass them directly into execute(), instead of binding them one by one - PDO will bind them internally, using PDO::PARAM_STR by default, which is not a problem most of time, save for only one case - LIMIT clause parameres.
It is not only greatly reduces amount of code, but also let you to reuse the same set of variables with different queries.
$data = array(
'us_id' => $_SESSION['id'],
'ca_name' => $_POST['ca_name'],
// and so on
);
$stmt->execute($data);
Of course, array keys have to match placeholders in the query. If your queries have different sets of placeholders, you will need different arrays as well.

putcsv formatting wrong when result is from pdo

I am trying to import data from a db via pdo and output the results to a csv file. I am able to output to a screen correctly but the formatting in the csv is wild, double names and no '\n'
<?php
require_once('auth.php');
$conn = new PDO("mysql:host=localhost;dbname=$dbname", $username, $pw);
if (($handle = fopen("nameList2.txt", "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, " ")) !== FALSE) {
$firstname = $data[0];
$lastname = $data[1];
$stmt = $conn->prepare("SELECT * FROM list WHERE FName = :firstname AND LName = :lastname");
$stmt->bindParam(':firstname', $firstname);
$stmt->bindParam(':lastname', $lastname);
$stmt->execute();
$result = $stmt->fetchAll();
//var_dump($firstname);
//var_dump($lastname);
//var_dump($result);
$fp = fopen('file.csv', 'w');
foreach($result as $chunk){
echo $chunk[4]." ".$chunk[6]." ".$chunk[7]." ".$chunk[10]." ".$chunk[11]."".$chunk[12]." ".$chunk[13]." ".$chunk[18]." ".$chunk[19]." ".$chunk[20]."<br />";
fputcsv($fp, $chunk);
}
fclose($fp);
}
fclose($handle);
//fclose($fp);
}
?>
You are feeding fputcsv bad data, so it's giving you bad output. Specifically, fetchAll retrieves each row as an array with both numeric and string keys, so each value appears twice.
Fix this by setting the fetch mode appropriately, for example
$result = $stmt->fetchAll(PDO::FETCH_NUM);
It's unclear what the problem with the line endings is -- you don't say, and I can't tell from the screenshot. What is certain is that fputcsv writes a single line feed as the line termination character. While the vast majority of programs will correctly detect and handle these Unix-style line endings, there are some others (e.g. Notepad) that won't.
Your problem with double names is because you doesn't use the method fetchAll() right:
you get the names twice in the $result.
Use that:
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
To fix the problem with \n try
ini_set('auto_detect_line_endings', true);

i have query that inserting values into MySQL database with array and for loop

i have query that inserting values into MySQL database with array and for loop.but when i submit form MySQL database showing double entry. First Record is empty and Second Record is with values? Why MySQL database showing First Record Empty Entry.i don't know what is reason behind it?
HERE My Function Code
<?php
if(isset($_REQUEST['order']))
{
$count=1;
$count++;
$total=$_POST['total'];
for ($i=1; $i<=$count; $i++){
$queryproduct=mysql_query("INSERT INTO shoppingcart VALUES ('','','','$uid','$email','".$_POST['product'][$i]."','".$_POST['userfile_name'] [$i]."','".$_POST['price'][$i]."','".$_POST['qty'][$i]."','".$_POST['amt'][$i]."','$total')") or die("Order Query Problem");
}
}
?>
Try to start your loop from 0, as the $_POST["pid"] variable is numbered from 0, as in second (working) example:
for($i=0; $i<$lenght; $i++){ ...
However, avoid using mysql_* functions as Matt Ball stated in his comment.
I'm going to ignore the security problems with this code first off, we can come back to that part later. Let's first deal with the problem that I'm seeing right way.
First Record is empty and Second Record is with values? Why MySQL database showing First Record Empty Entry.i don't know what is reason behind it?
$count=1;
$count++;
What is going on here? Your setting a $count equal to 1 and then your immediately incrementing it by one too 2 on the second line. Why are you doing that? Why not set it too two in the first place?
I would bet, that you're problem with the First Record being Empty starts right with those lines of code.
$total = $_POST['total'];
This is only used in the query once, so why assign it to another variable at all you are just wasting memory.
From the first example of your code, I would say that this would be the best execution you could get from it (again, not talking about security).
<?php
if(isset($_REQUEST['order']))
{
for ($i = 1, $count = 0; $i <= $count; ++$i)
{
$queryproduct = mysql_query
(
"INSERT INTO shoppingcart VALUES
(
'',
'',
'',
'$uid',
'$email',
'{$_POST['product'][$i]}',
'{$_POST['userfile_name'][$i]}',
'{$_POST['price'][$i]}',
'{$_POST['qty'][$i]}',
'{$_POST['amt'][$i]}',
'{$_POST['total']}'
);"
)
or die("Order Query Problem");
}
}
?>
Looking at your second set of code, this would probably be the best you could do with it.
<?php
if(isset($_REQUEST['order']))
{
for($i = 0, $p = count($_POST['product']); $i < $p; ++$i)
{
$queryproduct = mysql_query
(
"INSERT INTO shoppingcart VALUES
(
'',
'',
'{$_POST['pid'][$i]}',
'$uid',
'$email',
'{$_POST['product'][$i]}',
'{$_POST['userfile_name'][$i]}',
'{$_POST['price'][$i]}',
'{$_POST['qty'][$i]}',
'{$_POST['amt'][$i]}',
'{$_POST['total']}'
);"
)
or die("Order Query Problem");
}
}
?>
Finally, and this one is about security. We could make these statements safe if we used some of the non-deprecated functions found within the PHP Code Base.
PDO is the most common of these interfaces, and you can find all of the documentation you need to setup a PDO connection to your SQL Database.
<?php
if(isset($_REQUEST['order']))
{
$stmt = $dbh->prepare("INSERT INTO shoppingcart VALUES ('', '', ?, ?, ?, ?, ?, ?, ?, ?, ?);");
$stmt->bindParam(1, $pid);
$stmt->bindParam(2, $uid);
$stmt->bindParam(3, $email);
$stmt->bindParam(4, $product);
$stmt->bindParam(5, $name);
$stmt->bindParam(6, $price);
$stmt->bindParam(7, $qty);
$stmt->bindParam(8, $amt);
$stmt->bindParam(9, $total);
for($i = 0, $p = count($_POST['product']); $i < $p; ++$i)
{
$pid = $_POST['pid'][$i]);
$product = $_POST['product'][$i]);
$name = $_POST['userfile_name'][$i]);
$price = $_POST['price'][$i]);
$qty = $_POST['qty'][$i]);
$amt = $_POST['amt'][$i]);
$total = $_POST['total'];
}
$stmt->execute();
}
?>
These will take care of correctly escaping query statements for you. A massive help, when we all can't know every attack vector and the experts have already come up with code on how to fix the most common ones.

Categories