AJAX, PHP, MYSQL chat works but need minor modifications

I have an IM chat that I have set up on my site, it works fine but I need to have it so the user logs in using the username and email they used to sign up to the site. I also don’t want to deal with anything regarding gravatar. Any help would be extremely appreciated. That last question about the photo album I asked, I fixed it by the way. I didn’t know someone replied.

Here is ajax-chat.php:

[code]<?php

/* Database Configuration. Add your details below */

$dbOptions = array(
‘db_host’ => ‘’,
‘db_user’ => ‘’,
‘db_pass’ => ‘’,
‘db_name’ => ‘’
);

/* Database Config End */

error_reporting(E_ALL ^ E_NOTICE);

require “classes/DB.class.php”;
require “classes/Chat.class.php”;
require “classes/ChatBase.class.php”;
require “classes/ChatLine.class.php”;
require “classes/ChatUser.class.php”;

session_name(‘webchat’);
session_start();

if(get_magic_quotes_gpc()){

// If magic quotes is enabled, strip the extra slashes
array_walk_recursive($_GET,create_function('&$v,$k','$v = stripslashes($v);'));
array_walk_recursive($_POST,create_function('&$v,$k','$v = stripslashes($v);'));

}

try{

// Connecting to the database
DB::init($dbOptions);

$response = array();

// Handling the supported actions:

switch($_GET['action']){
	
	case 'login':
		$response = Chat::login($_POST['name'],$_POST['email']);
	break;
	
	case 'checkLogged':
		$response = Chat::checkLogged();
	break;
	
	case 'logout':
		$response = Chat::logout();
	break;
	
	case 'submitChat':
		$response = Chat::submitChat($_POST['chatText']);
	break;
	
	case 'getUsers':
		$response = Chat::getUsers();
	break;
	
	case 'getChats':
		$response = Chat::getChats($_GET['lastID']);
	break;
	
	default:
		throw new Exception('Wrong action');
}

echo json_encode($response);

}
catch(Exception $e){
die(json_encode(array(‘error’ => $e->getMessage())));
}

?>[/code]

Here are the classes, 1st is DB.class.php:

[code]<?php

class DB {
private static $instance;
private $MySQLi;

private function __construct(array $dbOptions){

	$this->MySQLi = @ new mysqli(	$dbOptions['db_host'],
									$dbOptions['db_user'],
									$dbOptions['db_pass'],
									$dbOptions['db_name'] );

	if (mysqli_connect_errno()) {
		throw new Exception('Database error.');
	}

	$this->MySQLi->set_charset("utf8");
}

public static function init(array $dbOptions){
	if(self::$instance instanceof self){
		return false;
	}
	
	self::$instance = new self($dbOptions);
}

public static function getMySQLiObject(){
	return self::$instance->MySQLi;
}

public static function query($q){
	return self::$instance->MySQLi->query($q);
}

public static function esc($str){
	return self::$instance->MySQLi->real_escape_string(htmlspecialchars($str));
}

}

?>[/code]

2nd is Chat.class.php:

[code]<?php

/* The Chat class exploses public static methods, used by ajax.php */

class Chat{

public static function login($name,$email){
	if(!$name || !$email){
		throw new Exception('Fill in all the required fields.');
	}
	
	if(!filter_input(INPUT_POST,'email',FILTER_VALIDATE_EMAIL)){
		throw new Exception('Your email is invalid.');
	}
	
	// Preparing the gravatar hash:
	$gravatar = md5(strtolower(trim($email)));
	
	$user = new ChatUser(array(
		'name'		=> $name,
		'gravatar'	=> $gravatar
	));
	
	// The save method returns a MySQLi object
	if($user->save()->affected_rows != 1){
		throw new Exception('This nick is in use.');
	}
	
	$_SESSION['user']	= array(
		'name'		=> $name,
		'gravatar'	=> $gravatar
	);
	
	return array(
		'status'	=> 1,
		'name'		=> $name,
		'gravatar'	=> Chat::gravatarFromHash($gravatar)
	);
}

public static function checkLogged(){
	$response = array('logged' => false);
		
	if($_SESSION['user']['name']){
		$response['logged'] = true;
		$response['loggedAs'] = array(
			'name'		=> $_SESSION['user']['name'],
			'gravatar'	=> Chat::gravatarFromHash($_SESSION['user']['gravatar'])
		);
	}
	
	return $response;
}

public static function logout(){
	DB::query("DELETE FROM webchat_users WHERE name = '".DB::esc($_SESSION['user']['name'])."'");
	
	$_SESSION = array();
	unset($_SESSION);

	return array('status' => 1);
}

public static function submitChat($chatText){
	if(!$_SESSION['user']){
		throw new Exception('You are not logged in');
	}
	
	if(!$chatText){
		throw new Exception('You haven\' entered a chat message.');
	}

	$chat = new ChatLine(array(
		'author'	=> $_SESSION['user']['name'],
		'gravatar'	=> $_SESSION['user']['gravatar'],
		'text'		=> $chatText
	));

	// The save method returns a MySQLi object
	$insertID = $chat->save()->insert_id;

	return array(
		'status'	=> 1,
		'insertID'	=> $insertID
	);
}

public static function getUsers(){
	if($_SESSION['user']['name']){
		$user = new ChatUser(array('name' => $_SESSION['user']['name']));
		$user->update();
	}
	
	// Deleting chats older than 5 minutes and users inactive for 30 seconds
	
	DB::query("DELETE FROM webchat_lines WHERE ts < SUBTIME(NOW(),'0:5:0')");
	DB::query("DELETE FROM webchat_users WHERE last_activity < SUBTIME(NOW(),'0:0:30')");
	
	$result = DB::query('SELECT * FROM webchat_users ORDER BY name ASC LIMIT 18');
	
	$users = array();
	while($user = $result->fetch_object()){
		$user->gravatar = Chat::gravatarFromHash($user->gravatar,30);
		$users[] = $user;
	}

	return array(
		'users' => $users,
		'total' => DB::query('SELECT COUNT(*) as cnt FROM webchat_users')->fetch_object()->cnt
	);
}

public static function getChats($lastID){
	$lastID = (int)$lastID;

	$result = DB::query('SELECT * FROM webchat_lines WHERE id > '.$lastID.' ORDER BY id ASC');

	$chats = array();
	while($chat = $result->fetch_object()){
		
		// Returning the GMT (UTC) time of the chat creation:
		
		$chat->time = array(
			'hours'		=> gmdate('H',strtotime($chat->ts)),
			'minutes'	=> gmdate('i',strtotime($chat->ts))
		);
		
		$chat->gravatar = Chat::gravatarFromHash($chat->gravatar);
		
		$chats[] = $chat;
	}

	return array('chats' => $chats);
}

public static function gravatarFromHash($hash, $size=23){
	return 'http://www.gravatar.com/avatar/'.$hash.'?size='.$size.'&amp;default='.
			urlencode('http://www.gravatar.com/avatar/ad516503a11cd5ca435acc9bb6523536?size='.$size);
}

}

?>[/code]

3rd is ChatBase.class.php:

[code]<?php

/* This is the base class, used by both ChatLine and ChatUser */

class ChatBase{

// This constructor is used by all the chat classes:

public function __construct(array $options){
	
	foreach($options as $k=>$v){
		if(isset($this->$k)){
			$this->$k = $v;
		}
	}
}

}

?>[/code]

4th is ChatLine.class.php

[code]<?php

/* Chat line is used for the chat entries */

class ChatLine extends ChatBase{

protected $text = '', $author = '', $gravatar = '';

public function save(){
	DB::query("
		INSERT INTO webchat_lines (author, gravatar, text)
		VALUES (
			'".DB::esc($this->author)."',
			'".DB::esc($this->gravatar)."',
			'".DB::esc($this->text)."'
	)");
	
	// Returns the MySQLi object of the DB class
	
	return DB::getMySQLiObject();
}

}

?>[/code]

5th is ChatUser.class.php:

[code]<?php

class ChatUser extends ChatBase{

protected $name = '', $gravatar = '';

public function save(){
	
	DB::query("
		INSERT INTO webchat_users (name, gravatar)
		VALUES (
			'".DB::esc($this->name)."',
			'".DB::esc($this->gravatar)."'
	)");
	
	return DB::getMySQLiObject();
}

public function update(){
	DB::query("
		INSERT INTO webchat_users (name, gravatar)
		VALUES (
			'".DB::esc($this->name)."',
			'".DB::esc($this->gravatar)."'
		) ON DUPLICATE KEY UPDATE last_activity = NOW()");
}

}

?>[/code]

Here is script.js, I also have Jscroll plugin and all other necessary js to make it work but I don’t think its necessary to post here at the moment.

[code]$(document).ready(function(){

// Run the init method on document ready:
chat.init();

});

var chat = {

// data holds variables for use in the class:

data : {
	lastID 		: 0,
	noActivity	: 0
},

// Init binds event listeners and sets up timers:

init : function(){
	
	// Using the defaultText jQuery plugin, included at the bottom:
	$('#name').defaultText('Nickname');
	$('#email').defaultText('Email (Gravatars are Enabled)');
	
	// Converting the #chatLineHolder div into a jScrollPane,
	// and saving the plugin's API in chat.data:
	
	chat.data.jspAPI = $('#chatLineHolder').jScrollPane({
		verticalDragMinHeight: 12,
		verticalDragMaxHeight: 12
	}).data('jsp');
	
	// We use the working variable to prevent
	// multiple form submissions:
	
	var working = false;
	
	// Logging a person in the chat:
	
	$('#loginForm').submit(function(){
		
		if(working) return false;
		working = true;
		
		// Using our tzPOST wrapper function
		// (defined in the bottom):
		
		$.tzPOST('login',$(this).serialize(),function(r){
			working = false;
			
			if(r.error){
				chat.displayError(r.error);
			}
			else chat.login(r.name,r.gravatar);
		});
		
		return false;
	});
	
	// Submitting a new chat entry:
	
	$('#submitForm').submit(function(){
		
		var text = $('#chatText').val();
		
		if(text.length == 0){
			return false;
		}
		
		if(working) return false;
		working = true;
		
		// Assigning a temporary ID to the chat:
		var tempID = 't'+Math.round(Math.random()*1000000),
			params = {
				id			: tempID,
				author		: chat.data.name,
				gravatar	: chat.data.gravatar,
				text		: text.replace(/</g,'&lt;').replace(/>/g,'&gt;')
			};

		// Using our addChatLine method to add the chat
		// to the screen immediately, without waiting for
		// the AJAX request to complete:
		
		chat.addChatLine($.extend({},params));
		
		// Using our tzPOST wrapper method to send the chat
		// via a POST AJAX request:
		
		$.tzPOST('submitChat',$(this).serialize(),function(r){
			working = false;
			
			$('#chatText').val('');
			$('div.chat-'+tempID).remove();
			
			params['id'] = r.insertID;
			chat.addChatLine($.extend({},params));
		});
		
		return false;
	});
	
	// Logging the user out:
	
	$('a.logoutButton').live('click',function(){
		
		$('#chatTopBar > span').fadeOut(function(){
			$(this).remove();
		});
		
		$('#submitForm').fadeOut(function(){
			$('#loginForm').fadeIn();
		});
		
		$.tzPOST('logout');
		
		return false;
	});
	
	// Checking whether the user is already logged (browser refresh)
	
	$.tzGET('checkLogged',function(r){
		if(r.logged){
			chat.login(r.loggedAs.name,r.loggedAs.gravatar);
		}
	});
	
	// Self executing timeout functions
	
	(function getChatsTimeoutFunction(){
		chat.getChats(getChatsTimeoutFunction);
	})();
	
	(function getUsersTimeoutFunction(){
		chat.getUsers(getUsersTimeoutFunction);
	})();
	
},

// The login method hides displays the
// user's login data and shows the submit form

login : function(name,gravatar){
	
	chat.data.name = name;
	chat.data.gravatar = gravatar;
	$('#chatTopBar').html(chat.render('loginTopBar',chat.data));
	
	$('#loginForm').fadeOut(function(){
		$('#submitForm').fadeIn();
		$('#chatText').focus();
	});
	
},

// The render method generates the HTML markup 
// that is needed by the other methods:

render : function(template,params){
	
	var arr = [];
	switch(template){
		case 'loginTopBar':
			arr = [
			'<span><img src="',params.gravatar,'" width="23" height="23" />',
			'<span class="name">',params.name,
			'</span><a href="" class="logoutButton rounded">Logout</a></span>'];
		break;
		
		case 'chatLine':
			arr = [
				'<div class="chat chat-',params.id,' rounded"><span class="gravatar"><img src="',params.gravatar,
				'" width="23" height="23" onload="this.style.visibility=\'visible\'" />','</span><span class="author">',params.author,
				':</span><span class="text">',params.text,'</span><span class="time">',params.time,'</span></div>'];
		break;
		
		case 'user':
			arr = [
				'<div class="user" title="',params.name,'"><img src="',
				params.gravatar,'" width="30" height="30" onload="this.style.visibility=\'visible\'" /></div>'
			];
		break;
	}
	
	// A single array join is faster than
	// multiple concatenations
	
	return arr.join('');
	
},

// The addChatLine method ads a chat entry to the page

addChatLine : function(params){
	
	// All times are displayed in the user's timezone
	
	var d = new Date();
	if(params.time) {
		
		// PHP returns the time in UTC (GMT). We use it to feed the date
		// object and later output it in the user's timezone. JavaScript
		// internally converts it for us.
		
		d.setUTCHours(params.time.hours,params.time.minutes);
	}
	
	params.time = (d.getHours() < 10 ? '0' : '' ) + d.getHours()+':'+
				  (d.getMinutes() < 10 ? '0':'') + d.getMinutes();
	
	var markup = chat.render('chatLine',params),
		exists = $('#chatLineHolder .chat-'+params.id);

	if(exists.length){
		exists.remove();
	}
	
	if(!chat.data.lastID){
		// If this is the first chat, remove the
		// paragraph saying there aren't any:
		
		$('#chatLineHolder p').remove();
	}
	
	// If this isn't a temporary chat:
	if(params.id.toString().charAt(0) != 't'){
		var previous = $('#chatLineHolder .chat-'+(+params.id - 1));
		if(previous.length){
			previous.after(markup);
		}
		else chat.data.jspAPI.getContentPane().append(markup);
	}
	else chat.data.jspAPI.getContentPane().append(markup);
	
	// As we added new content, we need to
	// reinitialise the jScrollPane plugin:
	
	chat.data.jspAPI.reinitialise();
	chat.data.jspAPI.scrollToBottom(true);
	
},

// This method requests the latest chats
// (since lastID), and adds them to the page.

getChats : function(callback){
	$.tzGET('getChats',{lastID: chat.data.lastID},function(r){
		
		for(var i=0;i<r.chats.length;i++){
			chat.addChatLine(r.chats[i]);
		}
		
		if(r.chats.length){
			chat.data.noActivity = 0;
			chat.data.lastID = r.chats[i-1].id;
		}
		else{
			// If no chats were received, increment
			// the noActivity counter.
			
			chat.data.noActivity++;
		}
		
		if(!chat.data.lastID){
			chat.data.jspAPI.getContentPane().html('<p class="noChats">No chats yet</p>');
		}
		
		// Setting a timeout for the next request,
		// depending on the chat activity:
		
		var nextRequest = 1000;
		
		// 2 seconds
		if(chat.data.noActivity > 3){
			nextRequest = 2000;
		}
		
		if(chat.data.noActivity > 10){
			nextRequest = 5000;
		}
		
		// 15 seconds
		if(chat.data.noActivity > 20){
			nextRequest = 15000;
		}
	
		setTimeout(callback,nextRequest);
	});
},

// Requesting a list with all the users.

getUsers : function(callback){
	$.tzGET('getUsers',function(r){
		
		var users = [];
		
		for(var i=0; i< r.users.length;i++){
			if(r.users[i]){
				users.push(chat.render('user',r.users[i]));
			}
		}
		
		var message = '';
		
		if(r.total<1){
			message = 'No one is online';
		}
		else {
			message = r.total+' '+(r.total == 1 ? 'person':'people')+' online';
		}
		
		users.push('<p class="count">'+message+'</p>');
		
		$('#chatUsers').html(users.join(''));
		
		setTimeout(callback,15000);
	});
},

// This method displays an error message on the top of the page:

displayError : function(msg){
	var elem = $('<div>',{
		id		: 'chatErrorMessage',
		html	: msg
	});
	
	elem.click(function(){
		$(this).fadeOut(function(){
			$(this).remove();
		});
	});
	
	setTimeout(function(){
		elem.click();
	},5000);
	
	elem.hide().appendTo('body').slideDown();
}

};

// Custom GET & POST wrappers:

$.tzPOST = function(action,data,callback){
$.post(‘php/ajax.php?action=’+action,data,callback,‘json’);
}

$.tzGET = function(action,data,callback){
$.get(‘php/ajax.php?action=’+action,data,callback,‘json’);
}

// A custom jQuery method for placeholder text:

$.fn.defaultText = function(value){

var element = this.eq(0);
element.data('defaultText',value);

element.focus(function(){
	if(element.val() == value){
		element.val('').removeClass('defaultText');
	}
}).blur(function(){
	if(element.val() == '' || element.val() == value){
		element.addClass('defaultText').val(value);
	}
});

return element.blur();

}[/code]

Sponsor our Newsletter | Privacy Policy | Terms of Service