Getting the last inserted messages from ajax chat - php

I'm building a chat application and having some issues. First of all I want the chat starts loading from database once the the user logs in.
function that gets the whole chat from db which is called by ajax
function getChatData(){
global $mysqli;
//echo $lastinseted= $mysqli->insert_id();
$sql = "SELECT `chat`.`message`,
`users`. `username`,
`chat`.`timestamp`
from `chat` JOIN `users` ON (`chat`.`user_id`=`users`.`user_id`)
ORDER BY `chat`.`timestamp` DESC limit 15";
try{
if($stmt=$mysqli->prepare($sql)){
echo returnJson($stmt);
$stmt->close();
$mysqli->close();
}else{
throw new Exception("An error occured while fetching record data");
}
}catch(Exception $e){
log_error($e, $sql, null);
echo 'fail';
}
}
here is the callback function:
function getChatCallback(data){
var h='';
for(var i=0, l=data.length;i<l;i++){
h+=data[i].username+' says: '+data[i].message+'<span style="color:gray"> at the time '+data[i].timestamp+'</span><br/>';
}
$('.messages').html(h);
setTimeout(getChat,1500);
}
this is the function that will insert the new messages to the database which is called once the user hits enter and it is called also by ajax call:
function putChatData($message,$room,$user_id){
global $mysqli;
$sql = "INSERT INTO `chat`
(`message`,`timestamp`,`room`,`user_id`)
VALUES (?,?,?,?)";
$timestamp = gmdate("Y-m-d H:i:s");
try{
if($stmt=$mysqli->prepare($sql)){
$stmt->bind_param('ssii',$message,$timestamp,$room,$user_id);
$stmt->execute();
$stmt->close();
$mysqli->close();
}else{
throw new Exception("An error occured while fetching record data");
}
}catch(Exception $e){
log_error($e, $sql, null);
echo 'fail';
}
}
the problem now is that I could insert the new messages to the db, but the first function the gets the chat, brings all that chat including the old ones before the user logs in. I tried to use timestamp or the last insert id but didn't work with me.

For this usecase you need to know the reg time and add a WHERE condition to your query
$sql = "SELECT `chat`.`message`,
`users`. `username`,
`chat`.`timestamp`
from `chat` JOIN `users` ON (`chat`.`user_id`=`users`.`user_id`)
WHERE `chat`.`timestamp` > $userRegDate
ORDER BY `chat`.`timestamp` DESC limit 15";

Related

Use prepared statements to check user override credentials, user override rights, and delete MySQL table Record

I am trying to build an override feature so users can manually remove a MySQL table row if they have the correct rights to do so. The user is prompted to input the same credentials used for program login as well as the uniqueID for the row that needs to be removed. Upon hitting the 'Submit' function, I run a series of if statements/ MySQL SELECT statements to check credentials, user rights and finally row Deletion with the result output as an alert.
However, my alert shows up blank and the row is not removed so I know there is a problem with my if statements. Upon testing, I believe the problem is when I try to use the previous query's results to run the next if statement logic.
How do I properly determine if the MySQL query returned a row using prepared statements?
All help is appreciated! Thank you!
My CODE:
if ((isset($_POST['overrideUsername'])) and (isset($_POST['overridePassword'])) and (isset($_POST['overrideUniqueID']))) {
$overridePasswordInput = $_POST['overridePassword'];
$overrideUsername = $_POST['overrideUsername'];
$overridePassword = ENCODE(($overridePasswordInput).(ENCRYPTION_SEED));
$roleID = '154';
$overrideUniqueID = $_POST['overrideUniqueID'];
//connect to the database
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if(mysqli_connect_errno() ) {
printf('Could not connect: ' . mysqli_connect_error());
exit();
}
$conn->select_db($dbname);
if(! $conn->select_db($dbname) ) {
echo 'Could not select database. '.'<BR>';
}
$sql1 = "SELECT users.id FROM users WHERE (users.login = ?) AND (users.password = ?)";
$stmt1 = $conn->prepare($sql1);
$stmt1->bind_param('ss', $overrideUsername, $overridePassword);
$stmt1->execute();
$stmt1->bind_result($userID);
//$result1 = $stmt1->get_result();
if ($stmt1->fetch()) {
$sql2 = "SELECT * FROM rolestousers WHERE (rolestousers.userid = ?) AND (rolestousers.roleid = ?)";
$stmt2 = $conn->prepare($sql2);
$stmt2->bind_param('ss', $userID, $roleID);
$stmt2->execute();
$stmt2->store_result();
if ($stmt2->fetch()) {
$sql3 = "DELETE * FROM locator_time_track_out WHERE locator_time_track_out.uniqueid = ?";
$stmt3 = $conn->prepare($sql2);
$stmt3->bind_param('s', $overrideUniqueID);
$stmt3->execute();
$stmt3->store_result();
if ($stmt3->fetch()) {
echo 'Override Successful! Please scan the unit again to close it out.';
} else {
echo 'Could Not Delete Record from the table.';
}//End $sql3 if.
} else {
echo 'User does not have override permission. Please contact the IT Department.';
}//End $sql2 if.
} else {
echo 'Your login information is incorrect. Please try again. If the issue persists, contact the IT Department.';
}//End $sql1 if.
//Free the result variable.
$stmt1->free();
$stmt2->free();
$stmt3->free();
$stmt1->close();
//Close the Database connection.
$conn->close();
}//End If statement
NOTE: I am definitely sure my DB connection information is correct. The issue resides after I connect into the database. I have also tested the code using only the first if statement and get the blank alert so I'm not making it past the first if statement.
EDIT:: My php Script was definitely failing, but even earlier than expected, at the following code:
$overridePassword = ENCODE(($overridePasswordInput).(ENCRYPTION_SEED));
So my issue is that I need to properly compare the password and encryption seed information. However, the previous programmer used the following line to do the same process (which is obviously unsafe):
$querystatement = "SELECT id, firstname, lastname, email, phone, department, employeenumber, admin, usertype FROM users WHERE login=\"".mysql_real_escape_string($user)."\" AND password=ENCODE(\"".mysql_real_escape_string($pass)."\",\"".mysql_real_escape_string(ENCRYPTION_SEED)."\")";
$queryresult = $this->db->query($querystatement);
I will need to fix this issue before I can even test the functionality of the if logic using prepared statements.
Your are passing wrong variable for delete query
$stmt3 = $conn->prepare($sql3);
Please refer [ http://www.plus2net.com/php_tutorial/pdo-delete.php ]

Function/Trigger already in use?

Im having problems getting an update function to work. The function marks badges as seen so that they are hidden from a notification window.
The function is called when the user clicks a button to mark them as seen.
I have two triggers on the table its trying to update which I think may be causing the problem.
The problem is : Can't update table 'users' in stored function/trigger because it is already used by statement which invoked this stored function/trigger.
Triggers:
Function:
function markAsSeen() {
require "connect.php";
$seen = mysqli_query($connection,"Update userbadges
INNER JOIN users ON users.id = userbadges.user_id
SET seen='1'
WHERE studentid = '".$_SESSION["studentid"]."' && seen=0") or die(mysqli_error($connection));
while ($data = mysqli_fetch_array($seen)) {
echo 'Done';
}
}
Is there any way around this?
Your issue is that the update_users_trigger trigger makes changes to the contents of the table users, while the query that is triggering the execution of this trigger also uses the table users.
You will need to adjust your query so that this deadlock doesn't occur. It isn't clear which fields are from each table, but I suspect that in your initial query you need to join on users so that you can query on studentid.
You could create a different function to get the userID that you need something like the following:
require_once "connect.php";
function getUserIDFromStudentID($student_id, mysqli $connection)
{
$query = 'SELECT id FROM users WHERE studentid = ? LIMIT 1';
$stmt = $connection->prepare($query);
// Replace the below s to an i if it's supposed to be an integer
$stmt->bind_param("s", $student_id);
$stmt->execute();
$result = $stmt->get_result();
$record = $result->fetch_object();
$result->free();
if ($record) {
return $record->id;
}
}
function markAsSeen(mysqli $connection) {
$user_id = getUserIDFromStudentID($_SESSION["studentid"], $connection);
if (! $user_id) {
throw new Exception('Unable to get user id');
}
$seen_query = 'UPDATE userbadges SET seen = 1 WHERE user_id = ? and seen = 0';
$stmt = $connection->prepare($seen_query);
// Replace the below s to an i if it's supposed to be an integer
$stmt->bind_param("s", $user_id);
$result = $stmt->execute();
if (! $result) {
die(mysqli_error($connection));
}
echo 'Done';
}
Passing the connection object around rather than requiring a global file to be required every time will allow for more flexibility.

Updating a form entry in php/mysql with checkboxes?

How can I allow the user submitting a form, to update his entry on "re-submission"
for example
12345678910 (unique id) , submitted the form with selections,
12345678910 , re-submitted with new selections
what's the function responsible for "automatically" updating such kind of form entries.
I know that I can use a check if the entry exists, but how do I update it if it exists and insert it in a new row if it doesn't ...
function checkstudentid($studentid)
{
$con = connectvar();
mysql_select_db("database1", $con);
$result = mysql_query(
"SELECT * FROM table WHERE studentid='$studentid' LIMIT 1");
if(mysql_fetch_array($result) !== false)
....
// I want to add the entry here since it doesn't exist...with checkboxes
// else , I want to update if it already exists
}
Now I'm also not completely positive if the above code will work...but this is what I have for starters, if there is any other way or if the method I'm using is "wrong" , I would appreciate the heads up...or if what I'm trying to is even possible (the way I'm doing it)...
NOTES
I only have one php file which the form submits to.
I am not using a login/registration system
I do not want to display all the data in a table using HTML, just an
"automatic" update if the studentid already exists in the table
If I were using a deprecated method to interact with a database, I would probably just do this:
<?php
function checkstudentid($studentid) {
$con = connectvar();
mysql_select_db("database1", $con);
$result = mysql_query(
"SELECT * FROM table WHERE studentid='$studentid' LIMIT 1");
$query = '';
if (mysql_num_rows($result) > 0) {
$query = "UPDATE table SET column1='$value_one', column2='$value_two' WHERE studentid='$studentid'";
} else {
$query = "INSERT INTO table VALUES('$new_id', '$value_one', '$value_two')";
}
if (mysql_query($query)) {
return true;
} else {
return false;
}
}
?>
But then again, I would use PDO to interact with the DB.
Here is a simple PDO example (you just have to write the function to return the connection):
<?php
function checkstudentid($studentid) {
$update = false;
$dbh = formPDOConnection();
$query = "SELECT studentid FROM table WHERE studentid=:id";
$stmt = $dbh->prepare($query);
$stmt->bindValue(':id', $studentid, PDO::PARAM_STR);
if ($stmt->execute()) {
if ($stmt->rowCount()) {
$update = true;
}
} else {
return 'failure to execute query';
}
// if we just need to update
if ($update) {
$update = "UPDATE table SET value1=:v1,
value2=:v2 WHERE studentid=:id";
$stmt = $dbh->prepare($update);
$stmt->bindValue(':id', $studentid, PDO::PARAM_STR);
$stmt->bindValue(':v1', $value_one, PDO::PARAM_STR);
$stmt->bindValue(':v2', $value_two, PDO::PARAM_STR);
} else {
$insert = "INSERT INTO table VALUES(:id,:v1,v2)";
$stmt = $dbh->prepare($insert);
$stmt->bindValue(':id', $new_id, PDO::PARAM_STR);
$stmt->bindValue(':v1', $value_one, PDO::PARAM_STR);
$stmt->bindValue(':v2', $value_two, PDO::PARAM_STR);
}
return $stmt->execute();
}
?>
Save yourself a headache and stop using mysql_*
You can use INSERT... ON DUPLICATE KEY UPDATE... on your mysql code instead use the logic in your PHP.
Here's a sample:
INSERT INTO `category` (`id`, `name`) VALUES (12, 'color')
ON DUPLICATE KEY UPDATE `name` = 'color';
Reference: http://dev.mysql.com/doc/refman/5.6/en/insert-on-duplicate.html

Better solution for sequential statement executions with PDO and PHP

I have 3 tables which I have to add a record to them after registration of a new user:
List of Tables:
I. users
... ... ... id (auto_increment, primary)
... ... ... email (email address of new user)
II. blogs
... ... ... id (auto_increment, primary)
... ... ... owner_id (= 'id' in 'users')
III. events
... ... ... id (auto_increment, primary)
... ... ... owner_id (= 'id' in 'users')
... ... ... blog_id (= 'id' in 'blogs')
In this situation I found 2 solutions for adding sequential records:
Solution 1: Using lastInsertId
<?php
try {
// Step 1: add a record to 'users' table and get lastInsertId
$query = $conn->prepare("INSERT INTO users (email) VALUES (:email)");
$query->bindParam(':email', $email);
$query->execute();
$user_id = $conn->lastInsertId();
// Step 2: add a record to 'blogs' table and get lastInsertId
$query = $conn->prepare("INSERT INTO blogs (owner_id) VALUES (:owner)");
$query->bindParam(':owner', $user_id);
$query->execute();
$blog_id = $conn->lastInsertId();
// Step 3: add a record to 'events' table
$query = $conn->prepare("INSERT INTO events (owner_id, blog_id) VALUES (:owner, :blog)");
$query->bindParam(':owner', $user_id);
$query->bindParam(':blog', $blog_id);
$query->execute();
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
Solution 2: Using single execute()
<?php
try {
// Step 1
$query = $conn->prepare("INSERT INTO users (email) VALUES (:email);" .
"INSERT INTO blogs (owner_id) VALUES ((SELECT id FROM users WHERE email = :email));" .
"INSERT INTO events (owner_id, blog_id) VALUES ((SELECT id FROM users WHERE email = :email), (SELECT id FROM blogs WHERE owner_id = (SELECT id FROM users WHERE email = :email)));");
$query->bindParam(':email', $email);
$query->execute();
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
Which solution should I choose for a better performance and security? Is there a better solution for my purpose?
Note: the connection created using PDO:
<?php
$options = array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
);
try {
$conn = new PDO("mysql:host=" . App::DB_HOST . ";dbname=" . App::DB_NAME . ";charset=utf8", App::DB_USERNAME, App::DB_PASSWORD, $options);
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
I would use transactions as a modification of 1st option.
$conn->beginTransaction();
try {
// Step 1: add a record to 'users' table and get lastInsertId
$query = $conn->prepare("INSERT INTO users (email) VALUES (:email)");
$query->bindParam(':email', $email);
$query->execute();
$user_id = $conn->lastInsertId();
// Step 2: add a record to 'blogs' table and get lastInsertId
$query = $conn->prepare("INSERT INTO blogs (owner_id) VALUES (:owner)");
$query->bindParam(':owner', $user_id);
$query->execute();
$blog_id = $conn->lastInsertId();
// Step 3: add a record to 'events' table
$query = $conn->prepare("INSERT INTO events (owner_id, blog_id) VALUES (:owner, :blog)");
$query->bindParam(':owner', $user_id);
$query->bindParam(':blog', $blog_id);
$query->execute();
$conn->commit();
}
catch (PDOException $e) {
// roll back transaction
$conn->rollback();
echo $e->getMessage();
die();
}
If you do some benchmarks you will see most time will be lost making the request.
From personal benchmarks on simple queries like this the execution time is very low.
The only thing that realy took time is the initialisation/prepare function.
There for making 3 requests will be slower then creating one large one.
EDIT:
Option 1 is the correct one because you do need to use id's, never link using a string or somethign else allways use id's.
Appart from that 1 (prepared) big query is better then 3x a prepare.
Edit. I misread the question at first, thought you are using exec(), not execute().
So, in fact you can combine both, as lastInsertId is just a PHP wrapper for Mysql's LAST_INSERT_ID()
But, as you need two ids, it will require additional mess with setting a variable. So, I doubt second option would worth, although feasible.
Just note that second would work only if PDO emulation mode is turned off
And surely there is no such question like "performance". Both will go perfectly.

PDO Replicating rows in different servers General Error

So I am trying to "move" selected rows from 1 table to another in different databases.
It in theory works (but if anyone wants to give any opinions please do, I am very new to PDO. I however keep getting a "SQLSTATE[HY000]: General error" error.
Any advice?
private function broken() {
try {
$sql = "SELECT * FROM `calls` WHERE `calls`.`status`=0 AND `calls`.`stage` < 4 AND `calls`.`answer` < (NOW() + INTERVAL 10 MINUTE)";
$query = $this->staging->query($sql);
while($row = $query->fetch(PDO::FETCH_ASSOC)) {
// Insert in production database:
$sql = "INSERT INTO `ivr_incomplete` (`id`,`sip_id`,`extension`,`caller_id`,`stage`,`status`,`survey_id`,`start`,`answer`,`hangup`,`end`) VALUES (:id, :sip_id, :extension, :caller_id, :stage, :status, :survey_id, :start, :answer, :hangup, :end)";
$query = $this->production->prepare($sql);
$query->execute($row);
// Delete from staging:
$sql = "DELETE FROM `calls` WHERE `id`='".$row['id']."'";
$this->staging->query($sql);
}
}
catch(PDOException $e) {
$this->informer("FATAL", "Unable to process broken IVR surveys. Error: ".$e->getMessage());
}
}
Two points:
You are preparing the INSERT on every iteration, which sort of eliminates half of the point of using a prepared statement - all you are using it for is escaping. One of the points of prepared statements is that the query is only parsed once, so if you need to execute the same query repeatedly with different values, calling prepare() once and then simply calling execute() with the different data sets can significantly boost performance.
This whole thing could be accomplished in 2 queries: Removed due to use of two separate DB connections
EDIT
Try this code:
You will likely need to adjust the error handling to meet your needs, particularly around how it is handled if there is an error with an INSERT, since I doubt you would want to break the whole operation and leave the rows that have been successfully processed in the source table.
private function broken() {
try {
// Fetch records to move
$sql = "
SELECT *
FROM `calls`
WHERE `status` = 0
AND `stage` < 4
AND `answer` < (NOW() + INTERVAL 10 MINUTE)
";
$query = $this->staging->query($sql);
if (!$query) {
$errorInfo = $this->staging->errorInfo();
throw new Exception("MySQL error at SELECT: $errorInfo[1] ($errorInfo[0]): $errorInfo[2]");
}
// Prepare the INSERT statement
$sql = "
INSERT INTO `ivr_incomplete`
(`id`,`sip_id`,`extension`,`caller_id`,`stage`,`status`,`survey_id`,`start`,`answer`,`hangup`,`end`)
VALUES
(:id, :sip_id, :extension, :caller_id, :stage, :status, :survey_id, :start, :answer, :hangup, :end)
";
if (!$stmt = $this->production->prepare($sql)) {
$errorInfo = $this->production->errorInfo();
throw new Exception("MySQL error at prepare INSERT: $errorInfo[1] ($errorInfo[0]): $errorInfo[2]");
}
// A list of the row IDs we are working with
$rowIds = array();
// Loop the results and insert them
for ($i = 1; $row = $query->fetch(PDO::FETCH_ASSOC); $i++) {
if (!$stmt->execute($row)) {
$errorInfo = $stmt->errorInfo();
throw new Exception("MySQL error at INSERT row $i (id: {$row['id']}): $errorInfo[1] ($errorInfo[0]): $errorInfo[2]");
}
$rowIds[] = (int) $row['id'];
}
// Delete from staging:
if ($rowIds) {
$sql = "
DELETE FROM `calls`
WHERE `id` IN (".implode(', ', $rowIds).")
";
if (!$this->staging->query($sql)) {
$errorInfo = $this->staging->errorInfo();
throw new Exception("MySQL error at DELETE: $errorInfo[1] ($errorInfo[0]): $errorInfo[2]");
}
}
} catch(PDOException $e) {
$this->informer("FATAL", "Unable to process broken IVR surveys (PDO). Error: ".$e->getMessage());
} catch (Exception $e) {
$this->informer("FATAL", "Unable to process broken IVR surveys (MySQL). Error: ".$e->getMessage());
}
}

Categories