Een AJAX chatsysteem met PHP

In dit voorbeeld zal ik laten zien hoe je een (basic) chatsysteem kan opzetten met gebruik van recente (of toch hedendaagse) technieken zoals jQuery, AJAX, … .

Het systeem zal bestaan uit 3 gedeeltes:

  • Een PHP gedeelte dat de berichten zal ophalen en deze zal omzetten naar JSON,
  • Een JavaScript gedeelte dat de berichten ophaalt en ook berichten kan versturen,
  • Een HTML gedeelte waar eigenlijk de lay-out van het chatsysteem zal in geplaatst worden.

 

Heads up!

Om dit voorbeeld te kunnen gebruiken heb je een webhost nodig met PHP en een MySQL database.

SQL

Maar  alvorens we hieraan kunnen beginnen zullen we eerst een tabel moeten aanmaken in een database waar we de berichten naar kunnen persisteren. In dit voorbeeld ga ik niets te fancy gebruiken, een ID, bericht en timestamp zullen voldoen. Hiervoor gebruik ik volgende SQL:

CREATE TABLE IF NOT EXISTS messages (
  id int(11) NOT NULL AUTO_INCREMENT,
  message varchar(255) NOT NULL,
  timestamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (id)
) ENGINE=InnoDB;

 

PHP service

Nu ga ik eens beginnen met het PHP gedeelte. In dit gedeelte zullen eigenlijk 2 dingen gebeuren, namelijk:

  • De berichten worden opgehaald,
  • Een nieuw bericht wordt opgeslagen.

Hiervoor gebruik ik de volgende code:
File: service.php

<?php 
$dbp = mysqli_connect("localhost", "root", "");
mysqli_select_db($dbp, "test");

header('Content-type: application/json');

function getMessages($timestamp) {
    global $dbp;
    $resultSet = mysqli_query($dbp, "SELECT message, UNIX_TIMESTAMP(timestamp) AS timestamp FROM messages WHERE UNIX_TIMESTAMP(timestamp) > '". mysqli_real_escape_string($dbp, $timestamp) ."' ORDER BY timestamp DESC LIMIT 10");
    $results = array();
    while ($row = mysqli_fetch_array($resultSet)) {
        $row["message"] = htmlentities($row["message"]);
        $row["timestamp"] = htmlentities($row["timestamp"]);
        $output = array(
            "msg" => $row["message"],
            "timestamp" => $row["timestamp"],
            "display" => date("H:i:s", $row["timestamp"]));
        array_push($results, $output);
    }
    return array_reverse($results);
}

function addMessage($message) {
    global $dbp;
    mysqli_query($dbp, "INSERT INTO messages (message) VALUES ('". mysqli_real_escape_string($dbp, $message) ."')");
}

if (isset($_GET["timestamp"])) {
    echo json_encode(getMessages($_GET["timestamp"]));
} else if (isset($_POST["msg"])) {
    addMessage($_POST["msg"]);
    echo '{"status": "ok"}';
}
 ?>

Bovenaan deze file staan eigenlijk de database login credentials, deze moeten uiteraard nog aangepast worden. Omdat ik met JSON ga werken staat vlak daaronder ook ineens de header die nodig is om JSON als response te krijgen.

JSON staat voor JavaScript Object Notation en is eigenlijk een String representatie van JavaScript objecten. Deze notatie is door de jaren heen zeer populair geworden, waardoor in elke programmeertaal wel een library te vinden is die de conversie kan doen van/naar JSON.

De eerste methode zorgt ervoor dat berichten gelezen kunnen worden. Ik heb het aantal berichten gelimiteerd op 10, zodat als er iemand het chatsysteem gebruikt, de laatste 10 berichten te zien krijgt. Verder gebeurt hier de conversie van een MySQL resultset naar een array naar eigen keuze. Deze array bevat de output waarden die we daarna rechtstreeks naar JSON kunnen omzetten.

In de tweede method wordt ervoor gezorgd dat berichten kunnen worden toegevoegd.  Zoals je kan zien voeren we alleen het bericht zelf in, de ID en de timestamp worden door MySQL zelf aangevuld.

JavaScript

Het tweede gedeelte of het JavaScript gedeelte is eigenlijk heel gelijkaardig aan het PHP gedeelte. Omdat we hier eigenlijk het client-gedeelte gaan verbinden met het service-gedeelte, zal hier eveneens een functie

addMessage()

en

getMessages()

aanwezig zijn.

File: assets/js/messageSystem.js

var timeEpoch = 0;
var scrollBottom = false;
setInterval(getMessages, 10000);

function sendMessage(msg) {
    $.ajax({
        type: "POST",
        cache: false,
        dataType: "json",
        url: "service.ph",
        data: { msg: msg },
        statusCode: {
            404: function() {
                alert("ERROR: Could not connect to the server.");
            }
        },
        success: function(data) {
            refreshMessages();
        },
        dataType: "json",
        async: true
    });
}

function displayError(errorMsg) {
    arr = new Object[1]();
    obj = new Object();
    obj.msg = "ERROR: " + errorMsg;
    obj.timestamp = 0;
    obj.display = "00:00:00";
    arr[0] = obj;
    displayMessages(arr);
}

function displayMessages(msgs) {
    if (msgs != null && msgs.length >= 1) {
        timeEpoch = msgs[msgs.length - 1].timestamp;
        $("#tmpMsg").hide();
        elem = $("#msgs");
        keepScroll = (elem[0].scrollHeight == elem.outerHeight());
        for (i in msgs) {
            $("#tmpMsg").append("[" + msgs[i].display + "]  " + msgs[i].msg + "<br />");
        }
        $("#tmpMsg").fadeIn("slow", function() { 
            $("#msgs").append($("#tmpMsg").html());
            $("#tmpMsg").remove();
            $("#msgs").append('<div id="tmpMsg"></div>');

            if (!scrollBottom || keepScroll) {
                elem[0].scrollTop = elem[0].scrollHeight;
                scrollBottom = true;
            }
        });
    }
}

function getMessages() {
    $.ajax({
        type: "GET",
        data: { timestamp: timeEpoch },
        url: "service.php",
        error: function() {
            displayError("Something went wrong.");
        },
        statusCode: {
            404: function() {
                displayError("Could not connect to server.");
            }
        },
        success: function(data) {
            displayMessages(data);
        },
        dataType: "json",
        async: true
    });
}

function addMessage(message) {
    $.ajax({
        type: "POST",
        data: { msg: message },
        url: "service.php",
        dataType: "json",
        success: function() {
            getMessages();
        }, 
        async: true
    });
}

$(document).ready(function() {
    getMessages();

    $("#sendBtn").click(function() {
        addMessage($("#msg").val());
        $("#msg").val("");
        $("#msg").focus();
    });

    $("#msg").keypress(function(e) {
        if (e.keyCode == 13) {
            $("#sendBtn").trigger("click");
        }
    });
});

Zoals gezegd bestaat deze code ook voornamelijk uit de functies

addMessage()

en

getMessages()

. Deze methodes zullen via AJAX de informatie doorsturen naar de webserver, en zullen zo het PHP script aanroepen dat we eerder gemaakt hebben.

De functie

displayMessages()

zal op zijn beurt er dan weer voor zorgen dat de berichten die binnen komen via

getMessages()

mooi geformat worden. Het eerste wat deze functie doet is ervoor zorgen dat de timestamp binnen de code up-to-date is, met dit systeem zal ervoor gezorgd worden dat bij elke oproep enkel de laatste berichten binnenkomen.

Daarna gaan alle nieuwe berichten in een tijdelijke div

#tmpMsg

terecht komen, deze div bevat telkens enkel de nieuwste berichten. Het voordeel is dat we daarna een animatie kunnen toevoegen zoals in dit geval een fade in. Na deze fade in worden alle berichten uit

#tmpMsg

overgezet naar

#msgs

en klaar is kees.

Het laatste deel is enkel nog om te controleren of de div naar de onderkant moet gescrolld worden of niet.

Helemaal onderaan deze file zal je enkele jQuery event-handlers terug vinden. Hiermee kan ik de “Send”-button en de “Enter”-knop koppelen aan de functieaddMessage(), waardoor dus een bericht verstuurd zal worden als één van deze events in actie komen.

HTML

Het HTML-gedeelte is redelijk eenvoudig en bestaat uit zaken die we hiervoor al opgesomd hebben zoals de divs

#tmpMsg

en

#msgs

. Een tekstveld om een bericht in te kunnen voeren en een button waarmee je dit bericht kan versturen.

File: index.html

<html>
    <body>
        <div id="msgs" style="width: 500px;height: 200px;overflow: scroll;">
            <div id="tmpMsg"></div>
        </div>
        <input type="text" id="msg" style="width: 450px;" placeholder="Message..." /><input type="button" style="width: 50px" id="sendBtn" value="Send!" />

        <script src="assets/js/jquery-1.7.2.min.js" type="text/javascript"></script>
        <script src="assets/js/messageSystem.js" type="text/javascript"></script>
    </body>
</html>

Vergeet niet om de locatie van jQuery aan te passen, ik heb gekozen om deze zelf te hosten, maar je kan ook een online versie gebruiken.

Als alles nu goed verlopen is zou het resultaat er ongeveer moeten uitzien als in de afbeelding onderaan.

Indien dit niet geval is, de structuur van het project zou er moeten uitzien als in de afbeelding hieronder. Als dat niet het geval is zou ik alles nog eens nalezen.

Download project

Download – ajax-chat-php.rar (34 kB)

Tagged , , , , .

g00glen00b

IT Consultant with a passion for JavaScript. Experienced in the Spring Framework and various JavaScript frameworks.