How to check for duplicates before inserting into database? - php

So I made a function to add photos to favorites, how do I make it so I don't keep adding the same images?
My code:
function addToFavorites($fileName)
{
global $conn;
$email = $_SESSION['email'];
$imageId = $_GET["id"];
$sql = "insert into favorites set UserEmail='".mysqli_real_escape_string($conn, $email)."', ImageID=".$imageId;
$result = mysqli_query($conn, $sql);
Any help would be great thanks!

You let the database do the work! Simply define a unique constraint or index on the table:
alter table favorites add constraint unq_favorites_useremail_imageid
unique (useremail, imageid);
With this constraint in place, the database will return an error if you attempt to insert a duplicate.
If you want to avoid the error, you can use on duplicate key update:
insert into favorites (UserEmail, ImageId)
values (?, ?)
on duplicate key update ImageId = values(ImageId);
Some notes about this:
The ? is a parameter placeholder. Learn to use parameters rather than munging values in query strings.
This does not use set. That is a MySQL extension. There is no advantage in this case; you might as well use the standard syntax.
The on duplicate key is a no-operation, but it prevents the code from returning an error when there is a duplicate.

If you want to avoid errors like Gordon Linof said you have execute query:
SELECT FROM favorites WHERE UserEmail='".mysqli_real_escape_string($conn, $email)."' AND ImageID=".$imageId
and if it returns 0 records to execute the insert one. This is the safest way.

Related

MySQLi UPDATE has an error with one column

The query I'm using (from php) is
"UPDATE articles SET
title='".$_POST['title']."',
contents='".$_POST['cont']."',
category='".$_POST['cat']."',
desc='".$_POST['desc']."'
WHERE stitle='".$_POST['stitle']."'";
and I get the error
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'desc='hello' WHERE stitle='banana'' at line 1.
If I remove desc='".$_POST['desc']."' the query works. The field 'desc' is varchar(150). I can insert text directly from phpMyAdmin, the field is definitely called 'desc', and $_POST['desc'] definitely captures a value (I tried using echo $_POST['desc']; and a value is passed). I tried changing the code to desc='test' and that doesn't work.
Any ideas?
I managed to resolve the issue. I created a new column in the table, copied the information from 'desc' into that column, deleted 'desc'. I ran the query with the new column name, and it works. I don't know what the issue was, but that fixed it.
The problem are your $_POST['desc'] contains an apostrophe. I recommend you to use on all parameters the function mysqli_real_escape_string (doc: http://be2.php.net/manual/en/mysqli.real-escape-string.php).
Also, try to escape all rows and tables with backticks, to avoid reserved words creating errors.
Your query example looks like this with them:
"UPDATE `articles` SET `title` = '".mysqli::real_escape_string($_POST['title'])."', `contents` = '".mysqli::real_escape_string($_POST['cont'])."', `category` = '".mysqli::real_escape_string($_POST['cat'])."', `desc` = '".mysqli::real_escape_string($_POST['desc'])."' WHERE `stitle` = '".mysqli::real_escape_string($_POST['stitle'])."'";
If you are programming with procedural style calls to mysqli functions, use:
"UPDATE `articles` SET `title` = '".mysqli_real_escape_string($link, $_POST['title'])."', `contents` = '".mysqli_real_escape_string($link, $_POST['cont'])."', `category` = '".mysqli_real_escape_string($link, $_POST['cat'])."', `desc` = '".mysqli_real_escape_string($link, $_POST['desc'])."' WHERE `stitle` = '".mysqli_real_escape_string($link, $_POST['stitle'])."'";
(Obviosuly, replace $link with the variable initialized when you do mysqli_connect())
Using these function, you can avoid these errors, and, also, a lot of SQL exploits. There's no required if the variable contains an integer, but, you always need to check the data passed to the SQL engine to avoid problems.
Is a good practice, to have some checks, for example, testing who integer vars contains integers, or doing escape with mysqli::real_escape_string. And, if something are incorrect on the input data, halt the process and don't request the SQL query.

How to test is row exists in the database

I have a table called user_bio. I have manually entered one row for username conor:
id: 1
age: 30
studying: Business
language: English
relationship_status: Single
username: conor
about_me: This is conor's bio.
A bio is unique to a user, and obviously, a user cannot manually set their bio from inserting it in the database. Consider the following scenario's:
Logged in as Conor. Since Conor already has a row in the database, I simply want to run an UPDATE query to update the field where username is equal to conor.
Logged in as Alice. Since Alice has no row in the database corresponding to her username. Then I want to run an INSERT query. For all users, all users will have to have their details inputted, and then updated correspondingly.
At the moment, I am struggling with inserting data in the database when no rows exist in the database.
Here is my current approach:
$about_me = htmlentities(trim(strip_tags(#$_POST['biotextarea'])));
$new_studying = htmlentities(trim(strip_tags(#$_POST['studying'])));
$new_lang = htmlentities(trim(strip_tags(#$_POST['lang'])));
$new_rel = htmlentities(strip_tags(#$_POST['rel']));
if(isset($_POST['update_data'])){
// need to check if the username has data already in the db, if so, then we update the data, otherwise we insert data.
$get_bio = mysqli_query($connect, "SELECT * FROM user_bio WHERE username ='$username'");
$row_returned = mysqli_num_rows($get_bio);
$get_row = mysqli_fetch_assoc ($get_bio);
$u_name = $get_row['username'];
if ($u_name == $username){
$update_details_query = mysqli_query ($connect, "UPDATE user_bio SET studying ='$new_studying', language ='$new_lang',
relationship_status = '$new_rel', about_me = '$about_me' WHERE username ='$username'");
echo " <div class='details_updated'>
<p> Details updated successfully! </p>
</div>";
} else {
$insert_query = mysqli_query ($connect, "INSERT INTO user_bio
VALUES ('', '$age','$new_studying','$new_lang','$new_rel', '$username', '$about_me'");
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
echo " <div class='details_updated'>
<p> Details added successfully! $row_returned </p>
</div>";
}
}
The UPDATE query works fine, when logged in as Conor. But again, INSERT does not work when logged in as Alice.
MySQL support INSERT ... ON DUPLICATE KEY UPDATE type of queries. So you do not need to make few queries to check existance of row in your php code, just add corrct indexes and let your DB take care about this.
You can read about such type of queries here
Here are a few things you could do to make it work:
Prevent SQL injection
As this is an important issue, and the suggested corrections provided below depend on this point, I mention it as the first issue to fix:
You should use prepared statements instead of injecting user-provided data directly in SQL, as this makes your application vulnerable for SQL injection. Any dynamic arguments can be passed to the SQL engine aside from the SQL string, so that there is no injection happening.
Reduce the number of queries
You do not need to first query whether the user has already a bio record. You can perform the update immediately and then count the records that have been updated. If none, you can then issue the insert statement.
With the INSERT ... ON DUPLICATE KEY UPDATE Syntax, you could further reduce the remaining two queries to one. It would look like this (prepared):
INSERT INTO user_bio(age, studying, language,
relationship_status, username, about_me)
VALUES (?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY
UPDATE studying = VALUES(studying),
language = VALUES(language),
relationship_status = VALUES(relationship_status),
about_me = VALUES(about_me);
This works only if you have a unique key constraint on username (which you should have).
With this statement you'll benefit from having the data modification executed in one transaction.
Also take note of some considerations listed in the above mentioned documentation.
NB: As in comments you indicated that you prefer not to go with the ON DUPLICATE KEY UPDATE syntax, I will not use it in the suggested code below, but use the 2-query option. Still, I would suggest you give the ON DUPLICATE KEY UPDATE construct a go. The benefits are non-negligible.
Specify the columns you insert
Your INSERT statement might have failed because of:
the (empty) string value you provided for what might be an AUTO_INCREMENT key, in which case you get an error like:
Incorrect integer value: '' for column 'id'
a missing column value, i.e. when there are more columns in the table than that you provided values for.
It is anyway better to specify explicitly the list of columns in an INSERT statement, and to not include the auto incremented column, like this:
INSERT INTO user_bio(age, studying, language,
relationship_status, username, about_me)
VALUES (?, ?, ?, ?, ?, ?)
Make sure you get notified about errors
You might also have missed the above (or other) error, as you set your error reporting options only after having executed your queries. So execute that line before doing any query:
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
And also add there:
error_reporting(E_ALL);
ini_set('display_errors', 1);
In a production environment you should probably pay some more attention to solid error reporting, as you don't want to reveal technical information in the client in such an environment. But during development you should make sure that (unexpected) errors do not go unnoticed.
Do not store HTML entities in the database
It would be better not to store HTML entities in your database. They are specific to HTML, which your database should be independent of.
Instead, insert these entities (if needed) upon retrieval of the data.
In the below code, I removed the calls to htmlentities, but you should then add them in code where you SELECT and display these values.
Separate view from model
This is a topic on its own, but you should avoid echo statements that are inter-weaved with your database access code. Putting status in variables instead of displaying them on the spot might be a first step in the right direction.
Suggested code
Here is some (untested) code which implements most of the above mentioned issues.
// Calls to htmlentities removed:
$about_me = trim(strip_tags(#$_POST['biotextarea']));
$new_studying = trim(strip_tags(#$_POST['studying']));
$new_lang = trim(strip_tags(#$_POST['lang']));
$new_rel = trim(strip_tags(#$_POST['rel']));
// Set the error reporting options at the start
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
if (isset($_POST['update_data'])) {
// Do not query for existence, but make the update immediately
$update_stmt = mysqli_prepare ($connect,
"UPDATE user_bio
SET studying = ?,
language = ?,
relationship_status = ?,
about_me = ?
WHERE username = ?");
mysqli_stmt_bind_param($update_stmt, "sssss",
$new_studying, $new_lang, $new_rel, $about_me, $username);
mysqli_stmt_execute($update_stmt);
$num_updated_rows = mysqli_stmt_affected_rows($update_stmt);
mysqli_stmt_close($update_stmt);
if ($num_updated_rows === 0) {
$insert_stmt = mysqli_prepare ($connect,
"INSERT INTO user_bio(age, studying, language,
relationship_status, username, about_me)
VALUES (?, ?, ?, ?, ?, ?)");
mysqli_stmt_bind_param($insert_stmt, "isssss",
$age, $new_studying, $new_lang, $new_rel, $username, $about_me);
mysqli_stmt_execute($insert_stmt);
mysqli_stmt_close($insert_stmt);
}
// Separate section for output
$result = $num_updated_rows ? "Details updated successfully!"
: "Details added successfully!";
echo " <div class='details_updated'><p>$result</p></div>";
}
Aside from security issues and bad coding practices, here are a couple things you can do.
You don't need to compare the name to check if the bio already exists. You can just count the number of rows returned. If it is more than zero, then the user bio already exists.
When comparing strings, === is preferred over ==. You can read about it and find out why but here is an example (2nd answer)
You should really look into either REPLACE INTO or ON DUPLICATE KEY UPDATE. Just using either of there 2, depending on your use case pick one, you can pretty much eliminate more than half of your currently displayed code. Basically, both will insert and if the record already exists, they updates. Thus, you wouldn't even need to check if the record already exists.

update the session field in database

I have a database. I had created a a table containing only one row in DB if it wasn't constructed before.
Why it has only 1 row is that I just use it to keep some info.
There is a field of TYPE NVARCHAR(100) which I want to use it to store session id,
and here comes the headache for me:
It seems that I can't even properly INSERT(I use phpmyadmin to check and it's blank) and UPDATE(syntax error...) it with a session id obtained from session_id(), which is returned as a string.
Here is the portion of my code relating to my action:
//uamip,uamport is in URL;I use $_GET[]
$_SESSION[uamport] = $_GET['uamport'];
$_SESSION[uamip] = $_GET['uamip'];
**$_SESSION[sid] = session_id();**
//construct
$sql="CREATE TABLE trans_vector(
`index` INT NOT NULL AUTO_INCREMENT,
`sid` NVARCHAR(100),
`uamip` CHAR(15),
`uamport` INT,
PRIMARY KEY (`index`)
)" ;
mysql_query($sql);
//insert(first time, so not constructed)
$sql="INSERT INTO trans_vector (sid,uamip,uamport) VALUES(
'$_SESSION[sid]',
'$_SESSION[myuamip]',
'$_SESSION[myuamport]'
)";
mysql_query($sql);
//update(from 2nd time and later, table exists, so I want to update the sid part)
$sql="UPDATE trans_vector SET sid="**.**$_SESSION[sid];
mysql_query($sql)
Now, when I use phpmyadmin to check the sid field after INSERT or UPDATE, It is blank;
But if I do this:
$vector=mysql_fetch_array(mysql_query("SELECT TABLES LIKE 'trans_vector'"));
and echo $vector[sid] ,then it's printed on webpage.
Another question is:
With the UPDATE statement above, I always get such error:
"Unknown column xxxxxx....(some session id returned, it seems it always translate it first and put it in the SQL statement, ** treating it as a column NAME** that's not what I want!)"
I tried some TYPE in CREATE statement, and also lots of syntax of the UPDATE statement(everything!!!) but it always give this error.
I am dealing trouble with ' and string representation containing a variable where the latter's value is actually what I want... and maybe the problem arise from type in CREATE and string representation in UPDATE statement?
Should CAST() statement helpful for me?
Wish you can help me deal with this...and probably list some real reference of such issue in PHP?
Thanks so much!!
$insert = "INSERT INTO trans_vector (`sid`, `uamip`, `uamport`) VALUES(
'".$_SESSION["sid"]."',
'".$_SESSION["myuamip"]."',
'".$_SESSION["myuamport"]."'
)";
this should solve at least some warnings, if not errors.
and for update...
$update = "UPDATE trans_vector SET `sid`='".$_SESSION["sid"]."';";
Notes about your code:
Array values have to be put into the string with operator '.' and cannot be inserted directly. Array indexes must be strings (note the ") or integers.
Column names should have `` around them. To insert a string with SQL, you have to put string into ''s, so the parser knows what is string and what column name. Without ''s parser is assuming you are stating a column.
and for mysql_escape_string, I assumed you handle that before storing data to sessions. Without those, you might can get unwanted SQL injections. And in case you did not do that, you can either do that (before you create queries):
foreach($_SESSION as $key => $value)
$_SESSION[$key] = mysql_escape_string($value);
or manually escape strings when you create a query.
As for the update statement, it’s clear that there are apostrophes missing. You always need apostrophes, when you want to insert a string value into the database. Moreover, you should use mysql_real_escape_string.
However, I think standard mysql is deprecated and has been removed in newer versions of PHP in favor of MySQLi and PDO. Thus you should switch to MySQLi or PDO soon.
You should also use apostrophes when referencing values within $_SESSION. Otherwise PHP will try to find a constanst with the name sid and later fallback to the string 'sid'. You will get into trouble if there once really is a constant called sid defined.
Here, the corrected update statement in mysql library:
$sql = "UPDATE trans_vector SET sid='" . mysql_real_escape_string($_SESSION['sid']) . "'";
Even better:
$sql = "UPDATE `trans_vector` SET `sid`='" . mysql_real_escape_string($_SESSION['sid']) . "'";
Using backticks makes clear for MySQL that this is a column name. Sometimes you will have column names that are called like reserved keywords in SQL. Then you will need apostrophes. A common example is a column called order for the sequence of entries.

php mysql_insert_id(); not working

Hi guys I was hoping from some help here, please.
I have a INSERT query to a table, after this is done I am calling:
mysql_insert_id();
In order to send the last ID inserted into the table to the next page like this:
$insertGoTo = "confirm_booking.php?booking_ID=" .$_POST['booking_ID']. "";
Unfortunately it does not work, all I get is a zero.
The table I am inserting into has an auto increment number and values are inserted into it.
I have also tried SELECT MAX(id) FROM mytable. This dosn't work neither.
I know that this problem has been talked about already. I read all posts but nothing came useful.
Many thanks Francesco
You have to use the value returned by MySql_Insert_Id () when you generate your link:
// your query
$newId = MySql_Insert_Id ();
$insertGoTo = "confirm_booking.php?booking_ID=" . $newId;
It is possible that your table does not have any AUTO_INCREMENT field!
It could also happen because you have two or more mysql connections at the same time.
In this case you should use a link identifier.
$link = mysql_connect( ... );
mysql_select_db('mydb', $link);
mysql_query('INSERT mytable SET abc="123"', $link);
$inserted_id = mysql_insert_id($link);
Some key points from the PHP Manual:
The ID generated for an AUTO_INCREMENT
column by the previous query on
success, 0 if the previous query does
not generate an AUTO_INCREMENT value,
or FALSE if no MySQL connection was
established.
If not having an AUTO_INCREMENT field is not your problem, you might want to try storing the result of the mysql_query call and using that as an argument to the id function
$result = mysql_query("...");
$id = mysql_insert_id($result);
Had an issue using a query like this:
INSERT INTO members (username,password,email) VALUES (...)
reason being that the id (which is my primary key and Auto Increment field) is not part of the query.
Changing it to:
INSERT INTO members (id,username,password,email) VALUES ('',...)
using a an empty value '' will have MySQL use the Auto Increment value but also allow you to use it in your query so you can return the insert id
mysql_insert_id may return 0 or false if your insert fails right?
So if you have trouble with mysql_insert_id not retunring what you expect confirm that you don't have a unique constraint or some other problem with your sql that would cause the insert to fail. Using max is a terrible idea if you consider this.
Make sure to put mysql_insert_id()after the
mysql_query($sql, $con); //Execute the query
Above query responsible for execute your Insert INTO ... command.
After you can get the last ID inserted
I have also suffer from this problem. Finally I found that the problem occur in my connection to the database. You can use this following connection code to connect the database then you can easily use mysqli_insert_id().
$db_connect = mysqli_connect("localhost", "root", "", "social");
Then you can use mysqli_insert_id() as
$id = mysqli_insert_id($db_conx);
I hope this will help you. I you have any problem then leave your comment.
The mysqli_insert_id function has been deprecated. This may be your problem.
Instead, try $mysqli->insert_id. See the documentation for more info.

My SQL triggers

Is it possible to set up a mysql trigger that fires back the id number of that record when ever there is an insert into the database AND how do i capture that using php?
Unless I don't fully understand your question, you don't need a trigger for this - just use the "last inserted ID" functionality of your database driver.
Here's an example using the basic mysql driver in PHP.
<?php
$db = mysql_connect( 'localhost', 'user', 'pass' );
$result = mysql_query( "insert into table (col1, col2) values ('foo', 'bar')", $db );
$lastId = mysql_insert_id();
This is a connection-safe way to obtain the ID.
As explained in the previous answers, you'd don't need to use a trigger to return the identity. You can use the mysql_insert_id() command as described in the [documentation][1].
However if you need to use the new insert id in a trigger, use NEW.[identity_column_name] as follows:
CREATE TABLE temp (
temp_id int auto_increment,
value varchar(10),
PRIMARY_KEY(temp_id)
);
CREATE TRIGGER after_insert_temp AFTER INSERT ON temp
FOR EACH ROW
BEGIN
DECLARE #identity;
SET #identity = NEW.temp_id;
-- do something with #identity
END
I'm not really sure what you're asking. Are you wanting to insert a row into the database and get the id it was assigned too? If so do this
printf("Last inserted record has id %d\n", mysql_insert_id());
You do not need a trigger to accomplish what you are trying to do.
Simply calling PHP's mysql_insert_id will return the ID generated from the last INSERT query executed.
Described here:
http://us2.php.net/manual/en/function.mysql-insert-id.php

Categories