Query works in SQL and not in PDO - php

I'm using PDO in PHP to connect to MySQL. My project is a chat app
Everytime someone sends a new message, I insert the message into table chat_messages, and I update a timestamp in table chat_users to indicate that that was the last time the user was active.
$sql = "INSERT INTO chat_messages
(email_sender, message, sent)
VALUES ('" . $email . "', '" . $message . "', '" . time() . "')";
$query = $pdo->prepare($sql);
if ($query->execute()) {
$sql2 = "UPDATE chat_users SET last_active = UNIX_TIMESTAMP()
WHERE email = '$email'";
$pdo->prepare($sql2)->execute();
// to test my query syntax is correct:
echo $sql2;
}
The timestamp is not being updated in the database. When i copy paste the output of echo $sql2 into phpMyAdmin, the query works.
What am i doing wrong?
Thank you

You're really missing out on a lot of the benefit of using prepared statements if you concat variables into the SQL like that. If you prepare with placeholders and bind your values, it will probably take care of your problems as well as being more secure against SQL injections.
$sql = "INSERT INTO chat_messages(email_sender, message, sent) VALUES (?, ?, ?)";
$query = $pdo->prepare($sql);
if ($query->execute([$email, $message, $time])) {
$sql2 = "UPDATE chat_users SET last_active = UNIX_TIMESTAMP() WHERE email = ?";
$pdo->prepare($sql2)->execute([$email]);
// to test my query syntax is correct:
echo $sql2;
}
If your query is failing (and even if it isn't) you should set PDO to throw exceptions when queries fail, so you'll get a descriptive error message as to what went wrong.

Related

How to run multiple SQL queries at the same time

I have two tables, one 'comment' and the other 'pendingcomment'. I want when I copy the data of the 'pendingcomment' in the 'comment' table then that data should be deleted from the 'pendingcomment' table.
This is my code.
<?php
include '../conn.php';
$id = $_GET['id'];
// sql to Insert and delete a record
$sql = "INSERT INTO comment (blogid, name, email, subject, message, date) SELECT blogid, name, email, subject, message, date FROM pendingcomment WHERE id= $id";
$sql .= "DELETE FROM pendingcomment WHERE id=$id";
if (mysqli_multi_query($conn, $sql)) {
// mysqli_close($conn);
header('Location: ../pendingcomments.php'); //redirect to the pending page
exit;
}
else {
echo "Error deleting record ";
}
?>
Result: Error deleting record
NEVER USE mysqli_multi_query()!!!
This function is extremely unsafe and causes a lot more problems than it solves. In fact, it doesn't solve any problems, it just creates more. You can't run queries at the same time from PHP! It is impossible to do so without threading or parallelization. If you need something like this then you can check out Swoole or ReactPHP but it's probably not needed in your case.
When executing queries you need to execute them one after another using prepared statements. This is how it should be done properly:
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$conn = new mysqli('localhost', 'user', 'password', 'test');
$conn->set_charset('utf8mb4'); // always set the charset
$id = $_GET['id'];
// begin atomic transaction
$stmt = $conn->begin_transaction();
// prepare statement for insert
$stmt = $conn->prepare('INSERT INTO comment (blogid, name, email, subject, message, date) SELECT blogid, name, email, subject, message, date FROM pendingcomment WHERE id= ?');
$stmt->bind_param('s', $id);
$stmt->execute();
// prepare statement for delete
$stmt = $conn->prepare('DELETE FROM pendingcomment WHERE id=?');
$stmt->bind_param('s', $id);
$stmt->execute();
// commit transaction
$conn->commit();
header('Location: ../pendingcomments.php'); //redirect to the pending page
exit;
The transaction ensures atomicity of the operations as long as your DB engine is InnoDB or a similar transaction engine. MyISAM is not. Remember to enable mysqli error reporting or it won't work.

PDO Binding in foreach fails at prepare

I would like to create a query that may or may not have more than one part. This means, I will be including an array and looping through it, and appending a query to the main SQL query, then finally prepare it.
First of all, I have defined the sql query
$sql = '';
then, I defined a foreach looping value
$arrayLoopValue = 0;
after that, I have created a foreach loop. In which I increased the arrayLoopValue, appended the sql with a new query based on the array's index.
foreach($questionsArray as $questionAnswerRow){
$arrayLoopValue = $arrayLoopValue + 1;
$sql = $sql .
'INSERT INTO gosurveys_surveys_questions_answers
SET survey_id = :survey_id_' . $arrayLoopValue .
', question_id = :question_id_' . $arrayLoopValue .
', user_email = :user_email_' . $arrayLoopValue .
', answer_type = :answer_type_' . $arrayLoopValue .
', question_answer = :question_answer_' . $arrayLoopValue .
', question_answer_creation_date = UTC_TIMESTAMP(); ';
}
The database / example for this query is NOT important, as all fields match and it's already empty. Only the structure, which is provided above, is required.
This fails at the following line.
$query = $this->conn->prepare($sql);
I tried to echo the query and see if there's something wrong. I got the following output:
INSERT INTO gosurveys_surveys_questions_answers
SET survey_id = :survey_id_1,
question_id = :question_id_1,
user_email = :user_email_1,
answer_type = :answer_type_1,
question_answer = :question_answer_1,
question_answer_creation_date = UTC_TIMESTAMP();
INSERT INTO gosurveys_surveys_questions_answers
SET survey_id = :survey_id_2,
question_id = :question_id_2,
user_email = :user_email_2,
answer_type = :answer_type_2,
question_answer = :question_answer_2,
question_answer_creation_date = UTC_TIMESTAMP();
Which is correct. After this prepare, there's a second foreach loop. But the function does NOT reach after the prepare statement.
I would like to know the reason. MYSQL says the following:
Uncaught exception 'PDOException' with message 'SQLSTATE[42000]: Syntax error or access violation: 1064 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 'INSERT INTO gosurveys_surveys_questions_answers
SET survey_id = ?, ques'
The name of the parameter is not the important thing.
If you want to run a query more than once then preparing it is a great idea but the parameter names are almost irrelevant. the important thing is the binding of new values to the paramters.
So lets assume this is your query
$sql = "INSERT INTO gosurveys_surveys_questions_answers
SET survey_id = :a,
question_id = :b,
user_email = :c,
answer_type = :d,
question_answer = :e,
question_answer_creation_date = UTC_TIMESTAMP()";
Notice the parameter names are irrelevant as long as they are something unique in the query string.
So now you prepare that query. This passes the basic query to the database where it is compiled and optimized, but is not actually run.
$stmt = $this->conn->prepare($sql);
Now within a loop that gets you the parameter you can run that prepared query 1000, 1,000,000 times if you like, all you have to do is bind new values to the parameters and execute the query, which passes the parameter values to the already prepared (compiled and optimized query) and runs it with the data you pass on the execute()
foreach($inArray as $array) {
// build the array of parameters and values
$params = [ ':a' => $array['field1']
':b' => $array['field2']
':c' => $array['field3']
':d' => $array['field4']
':e' => $array['field5']
];
// execute the prepared query using the new parameters
$stmt->execute($params);
}
here is the way to insert multiple rows of data, you prepare once and insert execute multiple times one prepared statement
$dbh = new PDO($dsn, $user, $pass, $options);
$arrayOfData = [...];
$stmt = $dbh->prepare('INSERT INTO table SET col = :val');
$dbh->beginTransaction();
foreach($arrayOfData as $data) {
$stmt->bindValue(':val', $data);
$stmt->execute();
}
$dbh->commit();
The idea of a prepared statement is that the statement is prepared once and then executed multiple times. Something like this:
$sql = 'INSERT INTO gosurveys_surveys_questions_answers
SET survey_id = :survey_id,
question_id = :question_id,
user_email = :user_email,
answer_type = :answer_type,
question_answer = :question_answer,
question_answer_creation_date = UTC_TIMESTAMP()';
$query = $this->conn->prepare($sql);
foreach($questionsArray as $questionAnswerRow) {
$query->execute([
":survey_id" => $questionAnswerRow["survey_id"],
// etc.
]);
}

Get last inserted ID in prepared statement

I need to get the last inserted ID for each insert operation and put it into array, I am trying to see what is the correct way of doing it.
Following this post Which is correct way to get last inserted id in mysqli prepared statements procedural style?
I have tried to apply it to my code but I am still not getting the right response.
if($data->edit_flag == 'ADDED')
{
$rowdata[0] = $data->location_name;
$rowdata[1] = 0;
$rowdata[2] = $data->store_id;
$query = "INSERT IGNORE INTO store_locations (location_name,total_items, store_id) VALUES (?,?,?)";
$statement = $conn->prepare($query);
$statement->execute($rowdata);
$id = mysqli_stmt_insert_id($statement);
echo "inserted id: " . $id;
}
I then realised that I am using a PDO connection so obviously mysqli functions wont work. I went ahead and tried the following
$id = $conn->lastInsertId();
echo "insert id: " . $id;
but the response is still empty? What am I doing incorrectly? For the lastInsertId(), should I be using $conn or $statement from here:
$statement = $conn->prepare($query);
$statement->execute($rowdata);
You are using lastInsertId() correctly according to the PDO:lastInsertId() documentation
$statement = $conn->prepare($query);
$statement->execute($rowdata);
$id = $conn->lastInsertId();
Some potential reasons why it is not working:
Is this code within a TRANSACTION? If so, you need to COMMIT the transaction after the execute and before the lastInsertId()
Since you INSERT IGNORE there is the potential that the INSERT statement is generating an error and not inserting a row so lastInsertId() could potentially be empty.
Hope this helps!
If you are using pdo,
$stmt = $db->prepare("...");
$stmt->execute();
$lastInsId = $db->lastInsertId();

not updating the sql database

i wrote the following code,but its not updating the database,,its a part of a script and it cease to work..cant find a way around it .. need suggestions
<?php
$link = mysql_connect('xxxxxxxx');
if (!$link) {
die('Could not connect: ' . mysql_error());
}
mysql_select_db("xxx", $link);
$usernames='aneeshxx';
echo $usernames;
$update = "INSERT sanjana SET $name ='$usernames'";
mysql_query($update, $link);
$update1 = "INSERT INTO sanjana (name)VALUES ($usernames)";
mysql_query($update1, $link);
?>
$update = "INSERT sanjana SET $name ='$usernames'";
this probably is meant as an UPDATE statement, so for an update it should be
$update = "UPDATE sanjana set name = '$usernames'";
I put name and not $name due to your second query and not seeing $name being defined anywhere. Be aware that this will change the value in the column name of every row in the sanjana table to the value of $usernames, normally a statement such as this gets limited by conditions, e.g. WHERE userid = 33
$update1 = "INSERT INTO sanjana (name) VALUES ($usernames)";
for an INSERT statement it needs to have the values quoted so
$update1 = "INSERT INTO sanjana (name) VALUES ('$usernames')";
Be wary that this way of putting variables directly into your query string makes you vulnerable to SQL injection, to combat this please use the PDO or mysqli extensions, they both protect you from injection by providing you with prepared statements ; plain old mysql_* is not recommended for use anymore.
using pdo you'd use prepared statements like this
<?php
// we got $usernames from wherever you define it
$pdo = new PDO('mysql:dbname=mydb;host=localhost','username','password');
// to insert
$statement = $pdo->prepare('INSERT INTO `sanjana` (name) VALUES (:name)');
// the following replaces :name with $usernames in a safe manner, defeating sql injection
$statement->bindParam(':name',$usernames);
$statement->execute(); // it is done
// to update
$statement = $pdo->prepare('UPDATE `sanjan` SET `name` = :name');
$statement->bindParam(':name',$usernames);
$statement->execute(); // it is done
so as you can see protecting your code from malicious input is not hard and it even makes your SQL statements a lot easier to read. Did you notice that you didn't even need to quote your values in the SQL statement anymore? Prepared statements take care of that for you! One less way to have an error in your code.
Please do read up on it, it will save you headaches. PDO even has the advantage that it's database independent, making it easier to use another database with existing code.
The right update sql clause is like so:
UPDATE table
SET column = expression;
OR
UPDATE table
SET column = expression
WHERE predicates;
SQL: UPDATE Statement
Your query should be like this:
$update = "UPDATE sanjana SET $name ='$usernames'";
mysql_query($update, $link);
Of course you need to specify a row to update (id), other wise, the whole table will set column $name to $usernames.
UPDATE:
Because you are inserting a data in empty table, you should first execute $update1 query then execute $update query. UPDATE clause will make no change/insert on empty table.
Problem 1: use the correct "insert into" (create new record) vs. "update" (modify existing record)
Problem 2: It's good practice to create your SQL string before you call mysql_query(), so you can print it out for debugging
Problem 3: It's also good practice to detect errors
EXAMPLE:
<?php
$link = mysql_connect('xxxxxxxx')
or die('Could not connect: ' . mysql_error());
mysql_select_db("xxx", $link);
$usernames='aneeshxx';
$sql = "INSERT INTO sanjana (name) VALUES ('" . $usernames + ")";
echo "sql: " . $sql . "...<br/>\n";
mysql_query($sql, $link)
or die(mysql_error());
You have INSERT keyword for your update SQL, this should be changed to UPDATE:
$update = "UPDATE sanjana SET $name ='$usernames'";

Odd Mysql issue on insert

Hy all,
Not sure what's going on here, but if I run this:
$query = 'INSERT INTO users
(`id`, `first_name`, `second_name`, `register_date`, `lastlogin_date`)
VALUES
("'. $user_id . '", "' . $first_name .'", "'. $second_name . '", "' . $date . '", "' . $date . ");';
$result = mysql_query($query);
I get no return, but if I change it to this it's fine:
$query = 'INSERT INTO users (`id`, `first_name`, `second_name`, `register_date`, `lastlogin_date`)
VALUES ("21021212", "Joe", "Bloggs", "20090202", "20090202");';
$result = mysql_query($query);
User id = bigint(20)
first name = varchar(30)
second name = varchar(30)
date = int(8)
At first I thought it was a issue with the vars but they are exactly the same and still don't work.
Any help appreciated.
Get into the habit of escaping all database inputs with mysql_real_escape_string- really, you should use some kind of wrapper like PDO or ADODb to help you do this, but here's how you might do it without:
$query = sprintf("INSERT INTO users ".
"(id, first_name, second_name, register_date, lastlogin_date)".
"VALUES('%s','%s','%s','%s','%s')",
mysql_real_escape_string($user_id),
mysql_real_escape_string($first_name),
mysql_real_escape_string($second_name),
mysql_real_escape_string($date),
mysql_real_escape_string($date));
$result = mysql_query($query);
and also check for errors with mysql_error
if (!$result)
{
echo "Error in $query: ".mysql_error();
}
What's the result from "mysql_error()"? Always check this, especially if something doesn't seem to be working.
Also, echo out $query to see what it really looks like. That could be telling.
Maybe the value of $date was "1111'); DELETE FROM users;"?
Seriously though? The problem is that isn't how you interact with your database. You shouldn't be passing in your data with your query. You need to specify the query, the parameters for the query, and pass in the actual parameter values when you execute the query. Anything else is inefficient, insecure and prone to bugs like the one you have.
By using PDO or something that supports parametrized queries, you'll find these kinds of issues go away because you are calling the database property. It is also much more secure and can speed up the database.
$sth = $dbh->prepare("INSERT INTO users (`id`, `first_name`, `second_name`, `register_date`, `lastlogin_date`) VALUES (?,?,?,?,?)")
$sth->execute(array($user_id ,$first_name , $second_name , $date, $date ));
In addition to echoing the query and checking mysql_error() as #GoatRider suggests:
Are you escaping your data properly? See mysql_real_escape_string()
You shouldn't end your queries with a semicolon when using mysql_query()
in $query = 'INSERT INTO users (id, first_name, second_name, register_date, lastlogin_date) VALUES ("' . $user_id . '", "' . $first_name . '", "' . $second_name . '", "' . $date . '", "' . $date . '");
are u giving the correct date format?? it might be the issue. otherwise the syntax is all fine.

Categories