0

I am developing a simple chat application using php. I am inserting message into database using ajax and I am reloading page after every 5 seconds so that if any new message arrives it gets refresh and the user will be able to see the new message but its not a good way to do that.I want a solution for this so that if any new message arrives the user can see that without reloading page after every 5 seconds. javascript code I have used is:

            $(document).ready(function() {
            debugger;
    var percentageToScroll = 100;
    var height = $('.panel-body').innerHeight();
    var scrollAmount = height;
     var overheight = jQuery(document).height() - jQuery(window).height();
jQuery(".divcls").animate({scrollTop: scrollAmount}, 900);    
});
setTimeout(function(){
   window.location.reload(1);
}, 5000);

        function checkMsg()
        {
            //alert("Enter");
            var message = document.getElementById("msg").value;
            //alert(message);
            if (message === "")
            {
                alert("Please Enter Message");
            } else
            {
                submitChat(message);
            }

        }
        ;
        function submitChat(message)
        {
            // alert("Enter");
            var msg = message;
            var xmlhttp = new XMLHttpRequest();

            xmlhttp.onreadystatechange = function () {
                if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
                    document.getElementById('msg').innerHTML = "";
                    location.reload();

                }
            }
            xmlhttp.open('GET', 'insert.php?msg=' + msg, true);
            xmlhttp.send();

        };

snippet code of chat box home is:

     <div style="overflow: scroll ;max-height: 650px; width: 100%;" class="divcls">
            <div class="panel-body">

<ul class="media-list">
    <?php
    include './connect.php';
                                        $sql = "select * from chatlog";
                                        $result = mysqli_query($con,$sql);
                                        while ($row = mysqli_fetch_array($result)) {
                                            ?>
                                    <li class="media">

                                        <div class="media-body">

                                            <div class="media">
                                                <a class="pull-left" href="#">
                                                    <img class="media-object img-circle " src="assets/img/user.png" />
                                                </a>
                                                <div class="media-body">
                                                    <span id="chatData"><?php echo $row["Msg"]; ?></span>
                                                    <br/>
                                                   <small class="text-muted"><?php echo $row["UserName"]; ?> | 23rd June at 5:00pm</small>
                                                    <hr />
                                                </div>
                                            </div>

                                        </div>
                                    </li>
                                    <?php
                                        }
                                        ?>
                                </ul>
                </div>
            </div>

insert page:

    <?php

require("connect.php");
$msg=$_GET['msg'];
$result=mysqli_query($con, "INSERT INTO chatlog(UserName, Msg) VALUES('admin','$msg')");

    header("location:index.php");
?>
riya
  • 51
  • 1
  • 1
  • 6
  • Have you considered using jQuery. Also this would be alot easyer with NodeJS. They have a wonderfull course on CodeSchool about that – Mathieu de Lorimier Mar 09 '16 at 15:10
  • You should use long polling/comet/web socket for that. Internet if full of examples. Just try using one of existing solutions. Generally you will need change server code to send message to push server after storing to database and your JS will also poll push server instead of your php code. – Evgeny Soynov Mar 09 '16 at 15:18

1 Answers1

0

Warning: this answer is a long one. So, grab your coffee and be prepared.

First of all, I would like to address this code:

<?php

require("connect.php");
$msg=$_GET['msg'];
$result=mysqli_query($con, "INSERT INTO chatlog(UserName, Msg) VALUES('admin','$msg')");

header("location:index.php");
?>

Please tell me this is not a direct copy and paste from your source code? If so, you severely need to edit this to protect against SQL Injection. To aid with this, please try something like the following instead:

<?php

require("connect.php");
$msg= $con->real_escape_string($_GET['msg']);
$result=mysqli_query($con, "INSERT INTO chatlog(UserName, Msg) VALUES('admin','$msg')");

header("location:index.php");
?>

You may also want to consider using prepared statements, but real_escape_string() will at least prevent injection by escaping potentially harmful messages. Consider reading this SO Question for more information about best practices for preventing SQL Injection attacks. As an additional security note, you should also look into applying filters to prevent XSS.

Anyway, I know that is not the topic of your question, but I always feel inclined to mention those sort of flaws when I see them. (Fixing them protects you, your website, and your users.) Onto your actual question, though!

I have seen a lot of "chat-box" implementations and most of them work in one of two ways:

  1. The webpage routinely queries/polls a backend script which returns the properly formatted HTML for the messages that are in the chatbox; or
  2. The webpage tracks all messages with an ID (sometimes using localStorage or sessionStorage), the webpage queries a backend script with the ID of the last received message, and the backend script returns any messages that have been received since that ID (any messages that are newer than the last received message).

Personally, I am a fan of the second method, but sometimes the first method is easier to implement. Also, to use the second method, your database would need to store an auto-incrementing unique identifier with your chatlog entries.


Method One Implementation

Because the second method can get a bit convoluted depending on how you do it, I'll write up an example of the first method.

The following would be my backend PHP code that would be polled (We'll call it get_chat.php):

<?php
// File: backend/get_chat.php
require_once('./connect.php');
$sql = "select * from chatlog";
$result = mysqli_query($con,$sql);
while ($row = mysqli_fetch_array($result)) {

?>
<li class="media">
    <div class="media-body">

        <div class="media">
            <a class="pull-left" href="#">
                <img class="media-object img-circle " src="assets/img/user.png" />
            </a>
            <div class="media-body">
                <span id="chatData"><?php echo $row["Msg"]; ?></span>
                <br/>
               <small class="text-muted"><?php echo $row["UserName"]; ?> | 23rd June at 5:00pm</small>
                <hr />
            </div>
        </div>

    </div>
</li>
<?php

} /* End While Loop */

?>

Note: This code will produce multiple spans with id="chatData". I have left the code like this because that is what your original code does as well. However, you should not have repeat IDs. I will leave that up to you to correct as you see fit.

Next, we'll need Javascript to interact with this code:

// We will want to set an initial timeout to start the refreshChat() 'cycle' (so to speak)
var timerId = setTimeout(function(){
                            refreshChat();
                        },
                3000
            ); /* End setTimeout(); */

function refreshChat(){
    var xmlhttp = new XMLHttpRequest();

    xmlhttp.onreadystatechange = function () {
        if (xmlhttp.readyState === 4) { // Request finished

            // Check if the status code indicates success
            if(xmlhttp.status === 200){
                var chatbox = document.getElementById('chatBox');
                chatbox.innerHTML = xmlhttp.responseText; // Set the inner-chatbox body
            } // Else, something went wrong.

            // Regardless of whether or not the request succeeded, the request has finished
            // so we should now set up a new timeout to automatically refresh the window again.

            // First, we'll try to clear the timeout so we don't potentially end up with two timeouts (which, in theory, would only happen if there is an error):
            clearTimeout(timerId);

            // Now we'll just go ahead and set the new timeout:
            timerId = setTimeout(function(){
                                        refreshChat();
                                    },
                                3000
                            ); /* End setTimeout(); */
        }
    } // End readyStateChange function

    var cacheBreaker = new Date().getTime(); // Current time to prevent caching
    xmlhttp.open('GET', 'backend/get_chat.php?anticache=' + cacheBreaker, true);
    xmlhttp.send();
};

Okay, now we have Javascript which calls a PHP script, and then receives the HTML of all of the latest chat messages. However, we're still not quite done. Now we will need to specify where that HTML goes. In the Javascript we are saying document.getElementById('chatBox');, but we do not actually have any elements with the ID chatBox currently.

To solve this, and to get the reloaded HTML into the right spot, all we need to do is change <ul class="media-list"> to <ul id="chatBox" class="media-list">. Now the Javascript will know which element we are inserting the returned HTML into, and it will be able to update the list of messages.

But we're not done just yet. Now we need to actually do something about the submitChat(message) function. We don't want it to reload the page, do we? And we probably don't want the user to submit a message and then have to wait around for 3 seconds before it appears, so, we should replace submitChat() with the following:

function submitChat(message){
    // alert("Enter");
    var msg = message;
    var xmlhttp = new XMLHttpRequest();

    xmlhttp.onreadystatechange = function () {
        // Handle this the same we handle refreshing the chat:
        if (xmlhttp.readyState === 4) { // Request finished

            // Check if the status code indicates success
            if(xmlhttp.status === 200){
                var chatbox = document.getElementById('chatBox');
                chatbox.innerHTML = xmlhttp.responseText; // Set the inner-chatbox body
            } // Else, something went wrong.

            // First, we'll try to clear the timeout so we don't prematurely run refreshChat():
            clearTimeout(timerId);

            // Now we'll just go ahead and set the new timeout:
            timerId = setTimeout(function(){
                                        refreshChat();
                                    },
                                3000
                            ); /* End setTimeout(); */
        }
    }
    xmlhttp.open('GET', 'insert.php?msg=' + msg, true);
    xmlhttp.send();

};

Now, to use this new Javascript, we'll need to slightly modify our insert.php code:

<?php

require("connect.php");
$msg= $con->real_escape_string($_GET['msg']);
$result=mysqli_query($con, "INSERT INTO chatlog(UserName, Msg) VALUES('admin','$msg')");

// And now we'll return the newest messages in the database:
include_once('get_chat.php');
?>

And that's it. We now have a chat-box that will automatically refresh itself, allow someone to post a message, and which has basic protection against SQL Injection attacks.

Again, I encourage you to look into adding XSS protection, and you may want to consider writing this using the second method described above. However, method two would be too long and complex to implement here, and XSS protection is out of the scope of this question, so I'll leave those up to you.

Note: I have not tested the code here, so it may contain some errors. I have attempted to read through all of the code to double check it, but I am sure I missed some minor errors here-and-there. Nonetheless, this should get you started down the right path. If something does not make sense, please do not hesitate to leave a comment and ask.

Community
  • 1
  • 1
Spencer D
  • 3,376
  • 2
  • 27
  • 43