Status online in the social network

02.09.2011

The essence of the problem is that the http protocol server cannot track in any way whether the user is still on the site or if he has left it for a long time if the user does not perform any active actions on the site. Therefore, it is up to the user's client (browser) to inform the server that the user is still online. And this problem is solved in the following way.

  1. The AJAX browser, when refreshing the page and after refreshing at a certain time interval, sends "garbage" to the server, for example, via POST it transmits an online variable with a value of true every 45 seconds after refreshing the page, when updating which it sends it immediately. Of course, it's bad that we are forced to clog the server in this way, forcing it to constantly connect to the database, but there is nowhere to go, and with the right choice of time, I chose 45 seconds, and the update method, and chose through AJAX, you can live with it :) Why exactly AJAX? And just imagine, you are looking at some pages on the site, the site is rather cumbersome with photos, and here you have a browser that forcibly updates the page with all the content every 45 seconds, and it’s far from a fact that after the update you will go to the very page on which you were. Silly isn't it? So here is option 1 - Use AJAX.
  2. The server, more precisely, in the mvc model, is the controller, when it detects the existence of a session, the correct user id in this session and the key of the superglobal array $_POST['online'] equal to logical true, sends its id $_SESSION['id'] and the current time on the server time() to the model to overwrite the `status` field in the database with this time for the user with this id.
  3. When displaying a list of users, or friends, or a queue for adding friends, or simply when viewing something in a profile in the view, past user data, the time of his last presence is displayed from the database and subtracted from the current server time. And if this difference is less than 60 (seconds), then the user is considered online and the corresponding inscription or icon is displayed, if more or exactly, then the user is considered unavailable and the corresponding inscription or icon is displayed.

One of the moments I missed is that the list of users, or rather the statuses of these users, should ideally be updated with AJAX at least every minute, so that the user, without performing active actions for a long time, receives up-to-date information about the activity of other users, and so he sees the state only until the last page refresh.

Finally, I'll show the AJAX code of the first part, since the code of the remaining parts is primitive and should not cause any difficulties.

AJAX library

ajax = {
	obj: false
	url: '/',
	init: function(){
			try {
			        this.obj = new XMLHttpRequest();
			}
			catch (trymicrosoft) {
				try {
				        this.obj = new ActiveXObject("Msxml2.XMLHTTP");
				}
				catch(othermicrosoft) {
				        try {
					        this.obj = new ActiveXObject("Microsoft.XMLHTTP");
					}
					catch (failed) {
					        ajax.obj = false;
					}
				}
			}
		},
	get: function(url_u){
		       if(!this.obj){
		                alert('Error initializing XMLHttpRequest!');
			        return false;
		        }
		        url = ajax.url;
		        this.obj.open('GET',url,true);
		        this.obj.onreadystatechange = this.answer;
		        this.obj.send(null);
	},
	post: function(_form){
		       if(!this.obj){
		                alert('Error initializing XMLHttpRequest!');
			        return false;
		        }
		        data = this.splitForm(_form);
		        this.obj.open('POST',this.url,true);
		        this.obj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		        this.obj.onreadystatechange = this.answer;
		        this.obj.send(data);
	},
	answer: function()
				{
					if (ajax.obj.readyState == 4)
					{
						if (ajax.obj.status == 200)
						{
							if(ajax.obj.getResponseHeader('Content-Type') == 'text/xml')
							{
								ajax.parseXML();
							}
							//else{ajax.parseText();}
						}
						else if (ajax.obj.status == 404){}
						else
						{
							alert("Error: status code is " + ajax.obj.status);
						}
					}
				},
	parseXML: function(){
			    if(this.obj.responseXML == null || this.obj.responseXML.documentElement == null){
			        try {
				        this.obj.responseXML.loadXML(this.obj.responseText)
				}
				catch(e){alert("Can't load");}
			    }
			    _xml = this.obj.responseXML.documentElement;
		            node_list = _xml.getElementsByTagName('error');
		            for(i=0; i<node_list.length; i++){
		                node = node_list.item(i);
				_text = node.text || node.textContent;
				id = node.getAttribute('id');
				try{
				document.getElementById(id).innerHTML = _text;
				}catch(e){}
			    }
			    _eval_list = _xml.getElementsByTagName('eval');
			    if(_eval_list.length > 0){
			        script = _eval_list.item(0).text || _eval_list.item(0).textContent;
			        try{eval(script);}catch(error){alert('AJAX: eval failed');}
			    }
	},
	parseText: function(){
		             text = this.obj.responseText;
			     alert(text);
	},
	splitForm: function(_form){
	                var_param = new Array();
	                _input = _form.getElementsByTagName('input');
	                _textarea = _form.getElementsByTagName('textarea');
	                _select = _form.getElementsByTagName('select');
	                _li = _input.length;
	                _lt = _textarea.length;
	                _ls = _select.length;
	                for(i=0; i<_li; i++){
	                        if(_input.item(i).type != 'checkbox'){
	                                try{_el = encodeURIComponent(_input.item(i).name)+'='+encodeURIComponent(_input.item(i).value);}
	                                catch(e){}
	                                _param.push(_el);
	                        }
	                        else if(_input.item(i).type == 'checkbox' && _input.item(i).checked){
	                                try{_el = (_input.item(i).name)+'='+encodeURIComponent(_input.item(i).value);}
	                                catch(e){}
	                                _param.push(_el);
	                        }
	                }
	                for(i=0; i<_lt; i++){
	                        if(_textarea.item(i).value.length > 0){
	                                try{_el = encodeURIComponent(_textarea.item(i).name)+'='+encodeURIComponent(_textarea.item(i).value);}
	                                catch(_e){}
	                                _param.push(_el);
	                        }
	                }
	                for(i=0; i<_ls; i++){
	                        if(_select.item(i).value.length > 0){
	                                try{_el = encodeURIComponent(_select.item(i).name)+'='+encodeURIComponent(_select.item(i).value);}
	                                catch(_e){}
	                                _param.push(_el);
	                        }
	                }
	                return _param.join('&');

	}
}
ajax.init();

Code for sending status to the server

<?php
	echo '<script type="text/javascript" src="/media/ajax.js"></script>
			<script type="text/javascript">
				function online()
				{
					ajax.post(document.onlineForm);
				}
				setInterval(function(){online();},45000);
				function addHandler(object,event,handler)
				{
					if (typeof object.addEventListener != \'undefined\')
						object.addEventListener(event, handler, false);
					else if (typeof object.attachEvent != \'undefined\')
						object.attachEvent(\'on\' + event, handler);
					else
						throw \'Incompatible browser\';
				}
				addHandler(window,\'load\',online);
			</script>';
?>

In this code, we connect the previously given library, which we have in the /media/ajax.js folder, and define the online() function, which will call the post method of the ajax class, passing it a form called onlineForm as a parameter, which will send to the server status.

We then set this function to call every 45 seconds, and define a cross-browser DOM level 2 event handler that, when the document is loaded, also calls the update() function.

Well, actually on our form named onlineForm with a single hidden field named online and a constant boolean parameter true, which pass it to the server with the post method that will be processed by the main site controller.

The only thing I want to add is that this code needs to be placed in a place that will always be present for a registered user who has visited the site. I placed it in the user menu module, since this module is displayed everywhere on my site and only when the user clicks on the site .

Last in our blog

Internet Marketing
04.11.2019