Quostin Posted June 24, 2013 Share Posted June 24, 2013 I been working on a chat for a website got most of it done and happy with it, until I monitored it on chrome through the network in task manager and saw that the more text is shown, the of a load it takes. Here is what I have. submitchat.php <? print "<BODY SCROLL='NO' bgcolor='#404040' text='black'>"; print "<body style='overflow: hidden'>"; print "<form action='chatbox.php' method='post' id='banana'>"; print " <input type='text' name='message' id='message' size='100'></textarea>"; print "<input type='submit' name='submit' value='Send'></form>"; ?> <script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script> <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery.validate/1.7/jquery.validate.min.js"></script> <script type="text/javascript"> $(document).ready(function(){ $("#banana").validate({ debug: false, submitHandler: function(form) { // do other stuff for a valid form $.post('chatcode.php', $("#banana").serialize(), function(data) { $('#log').load('chatlog.php'); $('#message').val(''); }); } }); }); </script> chatlog.php <? include ("connect.php"); ?> <head> <body bgcolor="black"> </head> <? $delete = "DELETE FROM `messages` WHERE `timestamp` < (NOW() - INTERVAL 2 HOUR)"; $deletenow = $db->exec($delete); $getmsg = "SELECT * from messages ORDER BY TIMESTAMP DESC"; $getmsg2 = $db->query($getmsg); while ($getmsg3 = $getmsg2->fetch(PDO::FETCH_ASSOC)) { { $find = "/me"; if ($getmsg3['function'] == $find) { $string1 = "<font color='tan'><i><b>$getmsg3[user] </b><font color='tan'>$getmsg3[message]</font></i>"; } else { $string1 = "<font color='$getmsg3[chatcolor]'><b>$getmsg3[user]: </b></font><font color='white'>$getmsg3[message]</font>"; } echo "$string1<br>"; } } ?> main.php <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> <head> <div id="main"> </head> <script type="text/javascript"> var auto_refresh; function start() { auto_refresh = setInterval(fresh, 10000); } function end() { auto_refresh = clearInterval(auto_refresh); } function fresh() { $('#log').load('chatlog.php'); } </script> <script type="text/javascript"> idleTimer = null; idleState = true; idleWait = 1200000; (function ($) { $(document).ready(function () { $('*').bind('mousemove keydown scroll', function () { clearTimeout(idleTimer); if (idleState == true) { $("#log").load('chatlog.php'); start(); } idleState = false; idleTimer = setTimeout(function () { // Idle Event $("#log").load('chatstop.php'); end(); idleState = true; }, idleWait); }); $("body").trigger("mousemove"); }); }) (jQuery) </script> <style> #topframe { width: 100%; position: absolute; left: 50%; top: 0%; ; color: #DDDAD7; height: 60%; overflow:auto; } #bottomframe { width: 100%; position: absolute; left: 50%; top: 60%; ; color: #DDDAD7; height: 40%; overflow:auto; } iframe {width: 100%; border: none; overflow-y: auto; overflow-x: hidden;} </style> <div id="topframe"> <iframe id="top" name="top" src="/home.php" frameborder="0" marginheight="0" marginwidth="0" width="100%" height="100%" scrolling="auto"></iframe> </div> <div id="bottomframe"> <style> body { background-color: #404040; background-image:url('rockblack.jpg'); } #log { color: white; position: absolute; width: 95%; height: 80%; left: 50%; ; top: 15%; padding:5px 5px; background: black; border-radius: 20px; overflow:auto; -moz-border-radius: 20px; /* Firefox 3.6 and earlier */ } </style> <? print "<body text='white' scrolling='1'>"; ?> <div id="chatbox"> <? include ("submitchat.php"); ?> </div> <div id="log"> <? include ("chatlog.php"); ?> </div> </div> </div> Basically, main has submitchat.php and chatlog.php and refreshes #log div with chatlog.php every 10 seconds. Works as it is shown. As I said, as the messages in the database get bigger, so does the chatlog.php file. Is there a way to lessen that load without having to do the whole chat in a different approach? Quote Link to comment Share on other sites More sharing options...
dalecosp Posted June 24, 2013 Share Posted June 24, 2013 Hmm ... a couple suggestions, maybe.Try getting rid of the delete on each pageload and just write an admin script to run from cron every two hours. Are you just running reverse chronological chat? "Select * from some_table" is usually overkill. If you only want, for example, to show the most recent conversation, would something like "select time, chat_text from chat_table order by time desc limit 20;" work ? Quote Link to comment Share on other sites More sharing options...
Psycho Posted June 24, 2013 Share Posted June 24, 2013 Well, one of the possible issues is that you are running a DELETE operation on every single call to update the chat log. DELETE's can be resource intensive - plus what is the reason behind deleting old messages? Seems that saving them could prove useful (e.g. someone posting inappropriate comments). You could change the logic to only SELECT the messages that were created in the last two hours rather than deleting the older ones and querying for ALL the messages. Better yet, have a JavaScript pass a timestamp since the last time it checked for messages and only return the new messages and append them to the output. Quote Link to comment Share on other sites More sharing options...
Quostin Posted June 24, 2013 Author Share Posted June 24, 2013 I'm going to remove delete and limit it to 20 or so and see how it goes. Quote Link to comment Share on other sites More sharing options...
Quostin Posted June 24, 2013 Author Share Posted June 24, 2013 Okay. I limit it to only 20 messages per load and removed the delete part and it is reading 1,631 b/s every 10 seconds. When looking at chats bigger than mine, it seems to only do like 230 B/s every 5 seconds, but have like 40-50 posts in the chat. I'm curious if it keeping the latest posts, and simply adding one line instead of refreshing the whole chat. Quote Link to comment Share on other sites More sharing options...
Psycho Posted June 24, 2013 Share Posted June 24, 2013 Below is a quick update to the chatlog.php script that should significantly help. But, I would still use the approach of passing a timestamp and only querying and returning the new messages since the client last requested an update. Also, here are some other tips: 1. Don't use short tags 2, Don't define a variable inside the loop if it will have the same value on each iteration of the loop 3. There were {} around a section of code with no control structure for it. 4. Don't use FONT tags, they've been deprecated for over a decade! Use style tags (or classes) 5. The output was always adding this to the output. Not only shoudl you not need it - it is invalid <head> <body bgcolor="black"> </head> Try this <?php include ("connect.php"); $query = "SELECT * from messages WHERE `timestamp` >= (NOW() - INTERVAL 2 HOUR) ORDER BY TIMESTAMP DESC"; $result = $db->query($query); $find = "/me"; $output = ''; while ($row = $result->fetch(PDO::FETCH_ASSOC)) { //Determine different style properties if($row['function'] == $find) { $recStyle = "font-style:italic;"; $userStyle = "color:tan;font-weight:bold;"; $msgStyle = "color:tan;" } else { $recStyle = ""; $userStyle = "color:{$row['chatcolor']};font-weight:bold;"; $msgStyle = "color:white;"; } //Append output to variable $output .= "<span style='{$recStyle}'>"; $output .= "<span style='{$userStyle}'>{$row['user']} " $output .= "<span style='{$msgStyle}'>{$row['message']}</span>"; $output .= "</span<br>\n"; } //Send the output echo $output; ?> Quote Link to comment Share on other sites More sharing options...
Psycho Posted June 24, 2013 Share Posted June 24, 2013 (edited) I'm curious if it keeping the latest posts, and simply adding one line instead of refreshing the whole chat. Your current code is pulling ALL the data in the query and sending it back to the client each time the call is made. Even if you only limit it to 20 records or the ones in the last two hours, it is inefficient and why I suggested a timestamp based approach so you only query and return the messages created since the last request and append them to the chat log. Or, you can implement a PUSH process where the data is sent to the browser automatically when new messages are created. I've never done it myself, but here is a pagewhere someone shows how to implement it: http://webscepter.com/simple-comet-implementation-using-php-and-jquery/ Edited June 24, 2013 by Psycho Quote Link to comment Share on other sites More sharing options...
Quostin Posted June 24, 2013 Author Share Posted June 24, 2013 Thanks for the help. I'm going to have to look at an alternate way to send chat right now. Psycho example is cleaner and easier to read, but the page loading went from 1600 B/s to 4.6 KB/s. Thanks for your suggestions! Quote Link to comment Share on other sites More sharing options...
Psycho Posted June 25, 2013 Share Posted June 25, 2013 Thanks for the help. I'm going to have to look at an alternate way to send chat right now. Psycho example is cleaner and easier to read, but the page loading went from 1600 B/s to 4.6 KB/s. Thanks for your suggestions! The change I provided does not use a LIMIT and instead pulls everything int he last two hours - because that was what you had originally. So, it would be pulling ALL the records int eh last two hours (not just 20 for example), so I would expect it to use more overhead. Quote Link to comment Share on other sites More sharing options...
Psycho Posted June 25, 2013 Share Posted June 25, 2013 Here is a brief overview of how you can update it to ONLY get new messages on subsequent AJAX requests. All the code below is for illustrative purposes and I do not guarantee it will work without modification. 1. Change the query process to check for a passed timestamp. If none was passed get all messages up to 2 hours (or whatever you choose). This should be a one-time process for each new user. 2. Also add another value to the SELECT list to get the current timestamp from the MySQL DB. (Also need to remove the "*" from the SELECT list and include only the fields you need to be more deficient) 3. Instead of passing back everything as a string (i.e. echo'ing the output), instead create an array with the output and the timestamp (which you can get from the DB results). This can be converted to a JSON format. The AJAX that request the data (assuming you are using JQuery) should set the datatype to JSON as well. Alternatively, you could just append the timestamp and output togetehr with a dash (-) or some other delimiteer and then parse the two values with string manipulation in JavaScript. 4. The receiving JavaScript process should take the "output" portion of the result to append it to the current output of messages. Then take the last_update timestamp from the returned value to update a JavaScript variable. That variable should then be included on the next AJAX request. Then the whole process repeats. Below is a mock up of the PHP code that could support this. I didn't do anything about the JavaScript changes that would be needed as I am short on time. <?php include ("connect.php"); if(isset($_GET['last_update'])) { //Should add validation of this value $last_update = "'{$_GET['last_update']}'"; } else { //Default for first request $last_update = "(NOW() - INTERVAL 2 HOUR)"; } $query = "SELECT function, chatcolor, user, message, CURRENT_TIMESTAMP as last_update FROM messages WHERE `timestamp` >= $last_update ORDER BY TIMESTAMP DESC"; $find = "/me"; $output = ''; while ($row = $result->fetch(PDO::FETCH_ASSOC)) { $last_update = $row['last_update']; //Determine different style properties if($row['function'] == $find) { $recStyle = "font-style:italic;"; $userStyle = "color:tan;font-weight:bold;"; $msgStyle = "color:tan;" } else { $recStyle = ""; $userStyle = "color:{$row['chatcolor']};font-weight:bold;"; $msgStyle = "color:white;"; } //Append output to variable $output .= "<span style='{$recStyle}'>"; $output .= "<span style='{$userStyle}'>{$row['user']} " $output .= "<span style='{$msgStyle}'>{$row['message']}</span>"; $output .= "</span<br>\n"; } //Send the results $result = array( 'last_update' => $last_update, 'output' => $output ) return json_encode($result); ?> Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.