Simple PHP chat quirk - php

I've been working on a quick and simple jQuery/PHP chat to put in my website for the visitors to communicate. I've extimated peaks of 200 simultaneous website users (connected users) with at most 10-20 people actually chatting.
Here's the quirk:
As I experienced already twice (thought it seems to be rather an unlikely event more than something happening after you perform something specific) the chat happens to load multiple messages which have already been red and display them.
Trying to keep the chat system as simple as possibile I came up with this code:
HTML CODE:
<div class="chat">
<ul class="chat">
<li class="chat" >
<h5 class="chat">Date</h5>
<h6 class="chat">Time</h6>
<h4 class="chat">User</h4>
<br/>
<q class="chat">Message</q>
</li>
</ul>
<input class="chat" placeholder="write something..."/>
</div>
As you can see I put a placeholder li element for the jQuery to take and use as a snippet to create new li elements with the actual messages and prepend them inside the ul element.
jQuery CODE:
Sending messages:
$(document).ready(function(){
chatSnippet = $('ul.chat').html(); // here chatSnippet is a global variable
$('ul.chat').html('');
$('input.chat').change(function(event){// Send your message
message = $(this).attr('value');
// first thing I perform an asynchronous POST to the receiving php script
$.post(
'php/chatRec.php',
{
user : currentUser,
message: message,
}
);
// meanwhile I add a new li element to the chat html with the content just submitted
date.setTime(event.timeStamp);
hours = ''+date.getHours();
if(hours.length < 2) hours = '0'+hours;
minutes = ''+date.getMinutes();
if(minutes.length < 2) minutes = '0'+minutes;
day = ''+date.getDate();
if(day.length < 2) day = '0'+day;
newChatMessage = chatSnippet.replace('Date', ''+day+' '+months[date.getMonth()]);
// here months is an array with the months names (in italian)
newChatMessage = newChatMessage.replace('Time', ''+hours+':'+minutes);
newChatMessage = newChatMessage.replace('User', connectedUser);
newChatMessage = newChatMessage.replace('Message', message);
$mess = $(newChatMessage);
$mess.hide().prependTo('ul.chat').fadeIn(500);
$(this).attr('value','');
});
refreshChat(''); // this function retrives new messages from the DB
// Here I perform a void refreshChat call so I'll get all the messages in the DB regardless from the currentUser (at page refresh)
});
Receiving messages:
// This code is placed outside (before) the .ready function
function refreshChat(user){// Receiving messages
$.post(
'php/chatInv.php',
{
user : user,
token: lastMessage // this variable contains the token of the last red message
},
function(data){
receivedMessages = jQuery.parseJSON(data);
for(message in receivedMessages){
message = receivedMessages[message].Message;
date = receivedMessages[message].Day.split('-');
time = receivedMessages[message].Time.split(':');
newChatMessage = chatSnippet.replace('Date', ''+date[2]+' '+months[parseInt(date[1])-1]);
newChatMessage = newChatMessage.replace('Time', ''+time[0]+':'+time[1]);
newChatMessage = newChatMessage.replace('User', receivedMessages[message].Sender);
newChatMessage = newChatMessage.replace('Message', message);
$mess = $(newChatMessage);
$mess.hide().prependTo('ul.chat').fadeIn(500);
lastMessage = receivedMessages[messages].token;
}
nextRefresh = setTimeout("refreshChat('"+currentUser+"')",2000);
// When I'm done I set a timeout of 2 secs and then perform another refresh
}
);
}
PHP CODE:
Receive a new message (I think the issue is in here):
mysql_connect("localhost", "root", "root") or die(mysql_error());
mysql_select_db("chat") or die(mysql_error());
$characters = array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
$token = $characters[rand(0,61)].$characters[rand(0,61)].$characters[rand(0,61)].$characters[rand(0,61)].$characters[rand(0,61)];
$all_Msgs = mysql_query("SELECT * FROM Messages ORDER BY ID");
$prev_Msg = array('ID' => 1 , 'Sender' => $_POST['user'], 'Message' => $_POST['message'], 'Day' => date("Y-m-d"), 'Time' => date("H:i:s"), 'token' => $token);
while($Msg = mysql_fetch_array($all_Msgs)){
$update_success = mysql_query("UPDATE Messages SET Sender='".$prev_Msg['Sender']."', Message='".$prev_Msg['Message']."', Day='".$prev_Msg['Day']."', Time='".$prev_Msg['Time']."', token = '".$prev_Msg['token']."' WHERE ID=".$Msg['ID']);
$prev_Msg = $Msg;
}
Basically what I do here is receive the new post message, generate a token and an array element (which is itself an array) containing the new entered datas, done this I perform a seuqence of UPDATE statements on a fixed size SQL table overriding the new datas on the first record and then overriding each record with the previous one (so that the last record will be finally lost).
Sending messages:
mysql_connect("localhost", "root", "root") or die(mysql_error());
mysql_select_db("chat") or die(mysql_error());
$receiver = $_POST['user'];
$token = $_POST['token'];
$all_Msgs = mysql_query("SELECT * FROM Messages ORDER BY ID");
$newMessages = array();
while($Msg = mysql_fetch_array($all_Msgs)){
if($Msg['token'] == $token) break;
if($Msg['Sender'] != $receiver) array_unshift($newMessages,$Msg);
}
echo json_encode($newMessages);
So I send the client the JSON encode of an array of all the records in the DB inserted after the last known message and whose author was not the querying client.
My suspects:
I came to the conclusion that when the message reception (server side) is being performed there is a time span when each message is taken from the DB, if a refresh is being performed in the meanwhile the message is not found and if that message was the one we were looking for as the last red message then the server will just select all the messages in the table and send them back.
The result is you see a bunch of messages you already red without your messages in between (cuz they were added to the view client side and the server script doesn't send you back your own messages)
Stated that:
I don't care if the messages aren't exactly in the actual insertion order: let's say A and B are chatting, the actual real messages order is BAB, but A may se the order ABB for his view is immediatly updated at input time (this helps me keep a 'fast-realtime' feel)
I don't care if some message is lost (like if it falls over the fixed DB table edge before someone can read it)
At this time I don't care much about actual efficency, speed and optimization
I know I should probalby handle the message insertion differently adding the new record and then updating the IDs only and delete the last record out. But if possible I'd like to keep this UPDATE-only fashion.
do you think my interpretation of the problem is right?
If not: what would then be the cause? / how can I fix that?
If yes: how can I fix that easily?
If the actual fix is rather complex: how actually likely to happen would be this quirk in a 10-20 users chat?
Thanks

I noticed this when I worked on a chat code too, the solution is to store the last message ID (set as an Auto Increment field in MySQL) in a session and search the database for messages where the ID is higher than that, rather than use the time() function.
if (!$_SESSION['message_id']]) {
// if there isn't a message_id, select the last seven entries in the message list
$sql = "SELECT messages.message_id, messages.message, users.username FROM (SELECT * FROM messages, users user.user_id = messages.user_id ORDER BY message_id DESC LIMIT 7) as new_tbl ORDER BY message_id ASC";
} else {
// if there is a message_id, select the messages sent since the last entry
$sql = sprintf("SELECT messages.message_id, messages.message, users.username FROM messages, users WHERE user.user_id = messages.user_id message_id > '%d'", $_SESSION['message_id']);
}
$data = array();
$query = mysql_query($sql);
while ($row = mysql_fetch_array($query)) {
// build the data array from the mysql result and set the message_id session to the id of the last message
$data[$i] = array('user' => $row['username'], 'message' => $row['message']);
$_SESSION['message_id'] = $row['message_id'] > $_SESSION['message_id'] ? $row['message_id'] : $_SESSION['message_id'];
$i++;
}
Obviously you'd need to escape the session!
If there isn't a message_id session, it loads the last 7 messages from the table (ordered descending, then orders those messages in ascending order). If there is a message_id session, it loads new messages.
In the while loop, it builds a data array (I send it to my script as JSON) and sets the message_id session as the message_id row, with a failsafe check to make sure the message_id session doesn't end up being lowered.
The SQL implies that you have a table of users with the user_id and username, and a table of messages with a user_id, message_id and message.

Related

Getting only one row from a loop in php and mysql

Hello family i have a big problem, i want to send the notifications to all the users who have commented on a certain post. Now the problem is that when i loop out the data i am finding a issue that some user id's are coming more than one time so my code is sending multiple notifications help me out here is the code:
//Inserting notifications to thread participants
$communityc = "SELECT * FROM communities_comments WHERE community_data_id=? AND commenter_id<>?";
$stmtcommunityc = $this->connect()->prepare($communityc);
$stmtcommunityc->execute([$CoumunityDataId,$CommenterId]);
$rowcommunityc = $stmtcommunityc->fetchAll();
$ownerIdc = $rowcommunityc['created_by'];
$community_idc = $rowcommunityc['community_id'];
foreach($rowcommunityc as $commentsrow){
$userId = $commentsrow['commenter_id'];
if($commenter_id != $ownerId){
$notify = "INSERT INTO alerts
(uid,username,alert,alert_status,alert_time,receiver_id,rdr_link)VALUES(?,?,?,?,?,?,?)";
$stmtnotify = $this->connect()->prepare($notify);
$stmtnotify->execute([1945,'batcall', 'There are some updates on one of the threads that you are a pacrticipant.', 'unread',$current_time, $userId, '../../community/single.php?id='.$CoumunityDataId.'']);
}
}

Get message_id of Telegram bot sendPoll message php

I have written a Telegram bot with PHP.
After sendPoll method boot it needs to wait 10 seconds for user answer - if user hasn't answered, the bot closes this Poll with method stopPoll. (Looks like Telegram's official #quizbot)
I use webhooks - the stopPoll method required message_id option for close Poll and I don't know how can I get the message_id of the latest sendPoll message in order to store it in the MySQL DB.
case '/sendpoll':
$i = '';
switch($i){
case 0:
$stt->sendteleg($data = ['text'=>"Are you ready? \xF0\x9F\x9A\x80"], $chat_id_call, "sendMessage");
sleep(2);
$dataSend = getpollquestions(0,6);
$stt->sendteleg($dataSend, $chat_id_call, "sendPoll");
$hasstate =$dbconn->hasuserstate($user_id_call);
if($hasstate){
$dbconn->updatestate($user_id_call,$message_id_call,'wait','poll');
}else {$dbconn->adduserstate($user_id_call,$message_id_call,'wait','poll');}
$state = $dbconn->getuserstate($user_id_call);
$statebolim = explode("-_-",$state);
sleep(10);
$datalimit = gettimeplus10($statebolim[2]);
if($datalimit){
$dat = [
'message_id' => json_encode($statebolim[0]+2)];
$stt->sendteleg($dat, $chat_id_call, "stopPoll");
}
You can see that I save message_id of the last callbackbutton that starts Poll in the DB and +2 it for stopPoll (+1 for "Are you ready" message and +1 for last sendPoll message). It's working, but there is exception if the user sends any message before the bot closes the Poll - message_id is wrong and stopPoll is not working.
Please tell me how can I make this code work?
i found solution, sending message(or Poll) with
$info = file_get_contents($bot_url."/sendPoll?" .http_build_query($dataSend));
returns all information about this action(chat_id, message_id, poll_id etc);
you can get all info by saving $info ;

How to display messages from the database on left and right?

'I made a simple chat box with php but the problem is i want to display my messages on the right and the other user messages on the left i made two while loops but they didn't work. My table is like this
(Sender - reciever - msg)
I want to display each message ordered by time and on different places right side and left side
if (isset($_POST['user_id'])){
$sender_id = $_POST['user_id'];
$sql = "SELECT * FROM messages_sys WHERE send_id=$sender_id AND reciever_id=$uid";
$sql_query = mysqli_query($conn, $sql);
print_r($sql_query);
you can use 'if' statement inside for loop :
foreach($messages as $message){
if($message->reciever == user_id){
<div class="right">$message</div>
}elseif($meesage->sender == user_id){
<div class="left">$message</div>
}
}
of course you have to open and close php tag before type html code inside

PHP Unique pageviews counter not working correctly

The following script updates the pageviews if its from a unique visitor. The page retrieves blog posts from databases and prints on the screen. When a blog post is visited first time the script should update its pageview field by 1. But the script is updating the pageview on every page refresh rather than recording only unique views.
if($_SESSION[$isPostID] != $isPostID)
{
try
{
$updatePageViews = $db2->prepare("UPDATE articles SET pageviews = pageviews+1 WHERE id = :id");
$updatePageViews->execute(array(':id' => $isPostID));
if($updatePageViews->rowCount() != 1)
{
#createLog("Unable to update pageviews.","Unable to update pageviews!!! Title = [".$istitle."].");
}
else{ $_SESSION[$isPostID] = $isPostID;}
}
catch(PDOException $updatePageViewsERR)
{
$subject = "Pageviews Updation--Update data into database. [PAGE= ".$istitle."]. Error Code: #15";
$text = $updatePageViewsERR->getMessage();
#createLog($subject,$text);
}
}
$isPostID is the unique ID assigned to every blog post in the database table.
Note: Session is already started in the script.
You have two errors in the first line.
First: you have no closing parenthesis in the condition. I guess it's just a typo, otherwise it would throw you fatal errors.
Second: you are comparing $isPostID to $isPostId which are two different variables. This may be exactly why it doesn't work.
See if it solves the problem

How can I limit or stop a form submission based upon a mysql count for a database drop-drop list?

I have a career day registration system that allow a student to select 3 unique career choices and submit the results to a mysql database. However, I would like to limit the selections to 90 people per career choice.
Example career day schedule:
Session 1: Nursing (limit to 90)
Session 2: Military (limit to 90)
Session 3: Pharmacy (limit to 90)
Is it possible to do a mysql count and pass the count value to a javascript variable? Also If the count is > 90 a javascript validation happens and doesn't allow you to save to database.
<?php
$sql = "SELECT * FROM mytable WHERE session1 = 'Nursing';
$query = mysql_query($sql);
$num_rows = mysql_num_rows($query);
?>
<script>
var count = <?php echo $num_rows; ?>
function Form_Validator(editform)
{
if((editform.value_session2.value == "Nursing" && count > 90)) { alert("Nursing is closed!"); return (false); }
return (true);
}
</script>
I've tried this method in several different ways... but the values are not being passed. Please help!
You shouldn't be doing this in javascript as any client side script can be bypassed.
What you need to do is do a count on the number of students enrolled in that course before insertion into the database. If count >= 90, then return an error saying the course is full. If count <= 90, then proceed with a statement that inserts the data, then return a success message.
I would do a simple and structured algorithm to work this out:
1) During page load I would only show the avaliable options.
Do a sql "group by", having all the "counts" and restrict the form appearence.
2) During the form submission check again about the possibility for a new applicant.
Do a simple count again, check if it is possible to receive a new submission. That's it. This would save some concurrency problems and other means of bypassing.
This sounds more secure and clear.
Of course you would script a REST service to chek application avaiability during a form filling moment, but that is more work into something it could be simple.
I understand this post is old, but here is what I did. When the user clicks on the Nursing session:
mysql_select_db($database_mySQLConnection, $mySQLConnection);
$query_registrant_count = sprintf("SELECT user_id FROM user_signup WHERE class_id = %s", GetSQLValueString($colname_registrant_count, "int"));
$registrant_count = mysql_query($query_registrant_count, $mySQLConnection) or die(mysql_error());
$row_registrant_count = mysql_fetch_assoc($registrant_count);
$totalRows_registrant_count = mysql_num_rows($registrant_count);
if ($totalRows_registrant_count > 19) {
$returnToCourseList = "../courseListFileName.php";
header(sprintf("Location: %s", $returnToCourseList . "?alert=" . urlencode("We're sorry, but this class is full. Please select another class or contact us for assistance.")));
exit;
}
Then in courseListFileName.php, use Pekka's suggestion for Handling alerts in php

Categories