Can XSS or anything else get through this? I coded a php chat that stores the text in a txt file and retrieves it, and I want to know if XSS can get past it or if someone can replace xhr.open("POST","uhh.php"); with something that contains the same php code but without htmlspecialchars or something like that.  What are the vulnerabilities? (More specifically, I don't want people putting html elements through the chat, and that also leads to security issues.)

This is uhh.php:

&lt;?php
$usr=$_POST["usr"];
$msg=$_POST["msg"];
if($usr&amp;&amp;$msg){
    $txt="$usr: $msg";
    $txt=htmlspecialchars(join("\n",str_split($txt,33)));
    $split=explode("\n",file_get_contents("uhh.txt") . $txt);
    while(count($split)&gt;10){
        $split=array_slice($split,1);
    }
    file_put_contents("uhh.txt",join("\n",$split) . "\n");
}
?&gt;
watchu lookeen at???


And this is the code to the html page (JavaScript included):

&lt;!DOCTYPE html&gt;
&lt;html&gt;&lt;head&gt;
&lt;title&gt;Chatting&lt;/title&gt;
&lt;style&gt;
#chatlog {
text-align:left;
border:1px solid black;
width:300px;
height:200px;
}
#chatbar {
width:300px;
}
&lt;/style&gt;
&lt;style type="text/css"&gt;&lt;/style&gt;&lt;/head&gt;
&lt;body&gt;
&lt;center&gt;
&lt;div id="chatlog"&gt;Bagelhead: lol&lt;br&gt;Bagelhead: yes t is&lt;br&gt;Abe: ok proxy off now&lt;br&gt;Bagelhead: gtg&lt;br&gt;Bagelhead: :P&lt;br&gt;Test: Test&lt;br&gt;Abe: &amp;lt;p&amp;gt;Test&amp;lt;/p&amp;gt;&lt;br&gt;Abe: Test&lt;br&gt;TEST: ab&lt;br&gt;TEST: abe&lt;br&gt;&lt;/div&gt;
&lt;input maxlength="9001" placeholder="Press / to chat" type="text" id="chatbar"&gt;
&lt;/center&gt;
&lt;script&gt;
setInterval(function(){
var xhr=new XMLHttpRequest();
xhr.open("GET","uhh.txt?a="+Math.random());
xhr.onload=function(){
document.getElementById("chatlog").innerHTML=xhr.responseText.replace(/\n/g,"&lt;br/&gt;");
}
xhr.send();
},1000)
var cb=document.querySelector("#chatbar"),usr="";
function chat(m){
var xhr=new XMLHttpRequest();
xhr.open("POST","uhh.php");
var fd=new FormData();
fd.append("usr",usr);
fd.append("msg",m);
xhr.send(fd);
}
window.onkeyup=function(e){
if(e.keyIdentifier=="U+00BF"){
cb.focus();
}else if(e.keyIdentifier=="Enter"){
if(usr){
chat(cb.value);
cb.value="";
}else{
usr=cb.value;
cb.placeholder="Press / to chat";
cb.value="";
cb.maxLength=9001;
}
}
}
&lt;/script&gt;

&lt;/body&gt;&lt;/html&gt;


uhh.txt is just a blank text file.
Looks safe to me, but I would change the way you request the server. This way, you send many requests to the server and for more then few people using it, the server could be flooded by these requests. It would however require switching txt file for script file. Then you could use so called long poll.

You are probably wondering what long poll is and how it works. Long poll is technique where client opens connection to the server and leaves it open. When new message comes, server sends it and closes the connection. Trick is, client immediately opens new connection. Same happens when old connection times out.

Problem here is, when you use PHP on server side, it just executes some code and closes the connection. So, you have 2 possibilities: Best idea is to use server written in node.js, which is made for such things (and there are other advantages like that you don't have to store the message anywhere, you just recieve it and immediately send it to all clients and other...). If you want or have to use PHP, then you must use the sleep() function. Then, you have while loop, that each for example 200 miliseconds check for new message in database and either sends it or sleeps for another 200 miliseconds.

If you want to try, here is part of my client code which takes care of server communication:

//function, that returns right kind of AJAX object based on browser
//I don't have worst case scenario (AJAX not supported) here, because I usually check for required support at the beginning of the script
function createAjax() {
    if (window.XMLHttpRequest) {
        return new XMLHttpRequest();
    } else {
        return new ActiveXObject('Microsoft.XMLHTTP');
    }
}

/*
Class that takes care of receiving new messages from server
PARAMS:
    longPollServerURL - string - URL of server file, which acts as long poll server
    lastIdGetURL - string - URL of txt file, where last message id is saved
    newMessageCallback - function - callback to get called when new message is received
        it is called with 4 params:
            id of the message, time when the message was sent as unix timestamp,
            nickname of the person who sent it, message text itself
*/
function ChatLongPoll(longPollServerURL, lastIdGetURL, newMessageCallback) {
    var mainContext = this,
        httpRequest = createAjax();

    //function that starts long poll and sets what should happen when connection ends
    this.startLongPoll = function() {
        httpRequest.onreadystatechange = function() {
            if (httpRequest.readyState == 4) {
                var _decodedResponse = JSON.parse(httpRequest.responseText);
                if (_decodedResponse.status == 'new') {
                    for (var i = 0; i &lt;_decodedResponse.messages.length; i++) {
                        newMessageCallback(_decodedResponse.messages[i].id, _decodedResponse.messages[i].time, _decodedResponse.messages[i].from, _decodedResponse.messages[i].messageText);
                        mainContext.lastMessageId = _decodedResponse.messages[i].id;
                    }
                }
                mainContext.openLongPoll();
            }
        };
        mainContext.openLongPoll();
    };

    //function that opens connection to the server
    this.openLongPoll = function() {
        httpRequest.open('GET', longPollServerURL + '?lastId=' + mainContext.lastMessageId, true);
        httpRequest.send(null);
    };

    //function that downloads ID of last message sent
    this.getLastMessageId = function() {
        var _id = false;
        httpRequest.onreadystatechange = function() {
            if (httpRequest.readyState == 4) {
                _id = httpRequest.responseText;
            }
        };
        httpRequest.open('GET', lastIdGetURL, false);
        httpRequest.send(null);
        return _id;
    };

    this.lastMessageId = this.getLastMessageId();
}


/*
Class that takes care of sending messages to server
PARAMS:
    newMessageServerURL - string - URL of file, which saves and validates the message
    callback - function - function to handle response from server (ok / wrongFormat / noName / ... status etc... (that depends on how you make your server))
*/
function ChatSendMessage(newMessageServerURL, callback) {
    var httpRequest = createAjax();

    httpRequest.onreadystatechange = function() {
        if (httpRequest.readyState == 4) {
            callback(JSON.parse(httpRequest.responseText));
        }
    };

    //function that sends the message to server and saves it to httpRequest.lastMessage
    this.sendMessage = function (from, messageText) {
        var L_postData = 'from=' + encodeURIComponent(from) + '&amp;messageText=' + encodeURIComponent(messageText);

        httpRequest.lastMessage = messageText;

        httpRequest.open('POST', newMessageServerURL, true);
        httpRequest.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        httpRequest.send(L_postData);
    };
}

/*
Short class that just simplifies access to those 2 classes before
PARAMS:
    newMessageServerURL - string - URL of file, which saves and validates the message
    longPollServerURL - string - URL of server file, which acts as long poll server
    lastIdGetURL - string - URL of txt file, where last message id is saved
    messageReceivedCallback - function - callback to get called when new message is received, it is called with 4 params: id of the message, time when the message was sent as unix timestamp, nickname of the person who sent it, message text itself
    sentMessageCallback - function - function to handle response from server (ok / wrongFormat / noName / ... status etc... (that depends on how you make your server))
*/
function ServerCommunicator(newMessageServerURL, longPollServerURL, lastIdGetURL, messageReceivedCallback, sentMessageCallback) {
    var longPoll = new ChatLongPoll(longPollServerURL, lastIdGetURL, messageReceivedCallback);
    var sendMessage = new ChatSendMessage(newMessageServerURL, sentMessageCallback);

    this.sendMessage = sendMessage.sendMessage;
    this.startLongPoll = longPoll.startLongPoll;
}