0

JS:

"use strict";

$(document).ready(function () {
    var chatInterval = 250; //refresh interval in ms
    var $userName = $("#userName");
    var $chatOutput = $("#chatOutput");
    var $chatInput = $("#chatInput");
    var $chatSend = $("#chatSend");

    function sendMessage() {
        var userNameString = $userName.val();
        var chatInputString = $chatInput.val();

        $.get("./write.php", {
            username: userNameString,
            text: chatInputString
        });

        $userName.val("");
        retrieveMessages();
    }

    function retrieveMessages() {
        $.get("./read.php", function (data) {
            $chatOutput.html(data); //Paste content into chat output
        });
    }


    $chatSend.click(function () {
        sendMessage();
    });

    setInterval(function () {
        retrieveMessages();
    }, chatInterval);
});

Write.php:

<?php
require("connect.php");

//connect to db
$db = new mysqli($db_host,$db_user, $db_password, $db_name);
if ($db->connect_errno) {
    //if the connection to the db failed
    echo "Failed to connect to MySQL: (" . $db->connect_errno . ") " . $db->connect_error;
}


//get userinput from url
$username=substr($_GET["username"], 0, 32);
$text=substr($_GET["text"], 0, 128);
//escaping is extremely important to avoid injections!
$nameEscaped = htmlentities(mysqli_real_escape_string($db,$username)); //escape username and limit it to 32 chars
$textEscaped = htmlentities(mysqli_real_escape_string($db, $text)); //escape text and limit it to 128 chars



//create query
$query="INSERT INTO chat (username, text) VALUES ('$nameEscaped', '$textEscaped')";
//execute query
if ($db->real_query($query)) {
    //If the query was successful
    echo "Wrote message to db";
}else{
    //If the query was NOT successful
    echo "An error occured";
    echo $db->errno;
}

$db->close();
?>

Read.php

<?php
require("connect.php");

//connect to db
$db = new mysqli($db_host,$db_user, $db_password, $db_name); 
if ($db->connect_errno) {
    //if the connection to the db failed
    echo "Failed to connect to MySQL: (" . $db->connect_errno . ") " . $db->connect_error;
}


$query="SELECT * FROM chat ORDER BY id ASC";
//execute query
if ($db->real_query($query)) {
    //If the query was successful
    $res = $db->use_result();

    while ($row = $res->fetch_assoc()) {
        $username=$row["username"];
        $text=$row["text"];
        $time=date('G:i', strtotime($row["time"])); //outputs date as # #Hour#:#Minute#

        echo "<p>$time | $username: $text</p>\n";
    }
}else{
    //If the query was NOT successful
    echo "An error occured";
    echo $db->errno;
}

$db->close();
?>

Basically everything works perfectly, except I want to allow people to copy and paste, but what the script is doing at the moment is updating every message at the chatinterval which is 250MS.

How can I make it so I can highlight a message and copy it?

So my question is, can I do this:

Can I make it only update the new messages that appear every 250-500MS instead of updating every last bit of HTML as that is a waste of resources (Especially if there was a lot of messages)

I hope you can help!

p.s. I don't want to use web sockets

  • 1
    Polling every 1/4 of a second is silly hopefully not more then 5 people use the chat, if not websockets, you could use server sent events, which is much more efficient than polling. You wouldn't need to change much either. Fix your sql injctions and XSS before it too late. – Lawrence Cherone Mar 08 '18 at 21:56
  • @LawrenceCherone How do I use server sent events? Could you show me – serversideman Mar 08 '18 at 21:57
  • Heres an example: https://stackoverflow.com/questions/49080653/how-do-i-put-this-on-real-time-i-already-put-async-true-but-it-doesnt-work/49081040#49081040 – Lawrence Cherone Mar 08 '18 at 21:57
  • no websocket with request 250ms, really?? basically you ddos your own server with your request – plonknimbuzz Mar 08 '18 at 22:27
  • Another example here https://github.com/lcherone/sse-chat-example – Lawrence Cherone Mar 10 '18 at 05:44

2 Answers2

2

To make it update just starting from the last message, get the ID of the last message, and then in your next $.get include the id of that message and get only messages that came after that.

And then use .append() in your javascript so you're not overwriting the whole thing.

Difster
  • 3,264
  • 2
  • 22
  • 32
  • What do you mean? How do I make it just update the new messages, could you explain a bit better for me? – serversideman Mar 08 '18 at 21:50
  • Have a hidden input field like so `` Then, each time you poll for new messages, just include the value for that field and in your query ONLY get messages after that one. Then, append the results to your existing messages rather than over writing them. Also, be sure to update that input field. – Difster Mar 08 '18 at 21:58
  • @Difster would probably be easier to avoid adding another input field, and just attach a `data` attribute to each message `

    `.

    – wolfson Mar 08 '18 at 21:59
  • @wolfson Yes that is smart wolfson – serversideman Mar 08 '18 at 22:00
  • That would work too @wolfson but I didn't want to introduce a whole new complexity to the user. – Difster Mar 08 '18 at 22:01
  • fair enough, it's all tradeoffs ;) – wolfson Mar 08 '18 at 22:02
0

It looks like you're already using jQuery. You can create a PHP script that only queries the database for entries newer than the newest one displayed, then use $.append to append the message to the <div> (or whatever other element) that holds it.

Also, as the commenter pointed out, you're still probably susceptible to SQL injection. Considering using PDO with prepared SQL statements.

wolfson
  • 192
  • 8