ساخت چت روم با PHP و jQuery فناوری Ajax

ساخت چت روم با PHP و jQuery فناوری Ajax

ساخت چت روم با PHP و jQuery – در این آموزش یاد خواهید گرفت که چگونه یک چت روم نیمه حرفه ای با استفاده از PHP و جی کوئری بسازید که از فناوری Ajax بهره می برد .

در این آموزش از :
1- PHP برای مدیریت درخواست ها در سمت سرور استفاده می کنیم
2- MYSQL برای ذخیره اطلاعات کاربر استفاده می کنیم
3- Javascript (jQuery) برای ارسال درخواست Ajax و تجربه یک برنامه SPA استفاده می کنیم .

2 بخش اصلی یعنی :

فایل app.js که برای ارسال درخواست و مدیریت سمت کلاینت است .
فایل process.php که برای مدیریت درخواست های ارسال شده کاربر می باشد مثل : ارسال پیام ، دریافت پیام


فایل app.js مدیریت سمت کلاینت با Javascript

ابتدا ارتفاع پنجره چت را متناسب با صفحه دستگاه تنظیم می کنید سپس با استفاده از متد Head درخواستی را می فرستیم که آیا پیام جدید برای کاربری فعلی وجود دارد یا خیر .

در صورتی که وجود نداشت status code 304 دریافت می کنیم ، اگر وجود داشت 200 دریافت می کنیم و مجدد این بار درخواست GET می فرستیم . این روند هر 2.5 ثانیه اجرا می شود تا اطلاعات را بروزرسانی کند .

همچنین برای ارسال پیام در صورتی که کاربر پیام را در keypad وارد کرده بود ، خالی نبود و دکمه ارسال را زد پیام را می فرستد ، البته در سمت سرور بررسی می شود که پیام ارسال شده برای کاربر دیگر (کاربر وجود دارد) .

$(document).ready(function() {

    let userMessageList = JSON.stringify({});
    let users = undefined;

    let requestCounter = 0;
    let oldLength = -1;


    const chatroomDOM = $('.chatroom');
    const messageViewDOM = $('#message-view');
    const keypadWrapperDOM = $('.keypad-wrapper');
    const sendMessageBtnDOM = keypadWrapperDOM.find("button");
    const keypadDom = keypadWrapperDOM.find("#keypad");
    const sendToDOM = keypadWrapperDOM.find("#send_to");

    const WH = window.innerHeight;
    const chatroomHeight = WH - 187;
    const httpURL = location.origin;


    // set default propery
    chatroomDOM.css("height", chatroomHeight + "px");
    chatroomDOM.find(".list-contact-wrapper,.message-view-wrapper").css("height", chatroomHeight + "px");


    sendMessageBtnDOM.click(sendMessageBtnHandler);

    // helper functions

    function helperTimestampToReadableTime(time) {
        const d = new Date();

        d.setTime(time * 1000);

        const year = d.getFullYear(),
            month = d.getMonth() + 1,
            day = d.getDate(),
            hour = d.getHours(),
            minute = d.getMinutes(),
            seconds = d.getSeconds();

        const readableTime = year + "/" + month + "/" + day + " | " + hour + ":" + minute + ":" + seconds;

        return readableTime;
    }

    function helperMessageViewReset() {
        messageViewDOM.html("");
    }

    function helperMessageViewDynamicContent() {
        if (sendToDOM.val() != "") {
            helperMessageViewReset();
            listMessagesOnChatroom(sendToDOM.val());
        }
    }


    // *********** chat ajax request ***********

    function addNewOwnMessageToMessageView(e) {
        const timestampSent = e.time_sent;
        const userRoom = sendToDOM.val();


        if (timestampSent) {
            const messageObject = {
                unique_user: 1,
                from_user: 2,
                timestamp_sent: timestampSent,
                message: keypadDom.val()
            }

            userMessageList = JSON.parse(userMessageList);
            userMessageList[userRoom].push(messageObject);
            userMessageList = JSON.stringify(userMessageList);

            listMessagesOnChatroom(userRoom)

            keypadDom.val("");


        }

    }

    function removeUnreadUserMessage(e) {

        if (e.user_room == "") return;
        const user = e.user_room;

        $(`[data-username=${user}]`).find("#contact-number-message").text("پیام جدیدی وجود ندارد");
    }

    function updateSeenUser() {
        getDataChat({ state: "snd_msg_state", from_user: sendToDOM.val() }, removeUnreadUserMessage, false);
    }

    function listMessagesOnChatroom(userRoom) {
        userMessageList = JSON.parse(userMessageList);
        const userMessages = userMessageList[userRoom];

        userMessageList = JSON.stringify(userMessageList);

        let counter = 0;
        helperMessageViewReset();
        for (const message of userMessages) {
            const messageDetails = {};
            counter++;
            messageDetails.who = message.unique_user != message.from_user ? "owner" : "other";
            messageDetails.number = counter;
            messageDetails.time = helperTimestampToReadableTime(message.timestamp_sent);
            messageDetails.content = message.message;
            generateMessageBox(messageDetails);
        }

        const currentLength = userMessages.length;
        if(oldLength == -1 || oldLength != currentLength){
        oldLength = currentLength;
        updateSeenUser();
        }

    }

    function addUserUnreadMessagesToList(e) {

        if (e === undefined) return;

        const messageList = e;

        for (const message of messageList) {
            const uniqueUname = message["unique_user"];
            userMessageList = JSON.parse(userMessageList);
            let oldMessage = userMessageList[uniqueUname];
            oldMessage = oldMessage[oldMessage.length - 1];
            const newMessage = message;


            if (oldMessage === undefined || oldMessage.timestamp_sent != newMessage.timestamp_sent) {
                
                userMessageList[uniqueUname].push(message);
            }

            userMessageList = JSON.stringify(userMessageList);
        }



    }


    function addUserUnreadMessagesElements(e) {
        if (e === undefined) return;

        const user = e['from_user'];

        const messageNumber = e['countMessage'];

        const msg = messageNumber == 0 ? "پیام جدیدی وجود ندارد" : messageNumber + " پیام جدید";


        $(`[data-username=${user}]`).find("#contact-number-message").text(msg)

    }



    function getUserUnreadMessages() {

    	

        for (const user of users) {
            const userName = user.username;

            requestCounter++;

            getDataChat({ state: "rcv_msg", from: userName, count: true }, addUserUnreadMessagesElements, false);


            if (requestCounter == 1)
                getDataChat({ state: "rcv_msg", from: userName, all_msg_unique: true }, addUserUnreadMessagesToList, false);
            else {
                getDataChat({ state: "rcv_msg", from: userName }, addUserUnreadMessagesToList, false);
                helperMessageViewDynamicContent();
            }
        }
    }


    getDataChat({ state: "rcv_usr" }, userRcvHandler, false);

    function userRcvHandler(e) {
        users = e;
        let counter = 1;

        for (const user of users) {
            const userName = user.username;
            userMessageList = JSON.parse(userMessageList);
            userMessageList[userName] = [];
            userMessageList = JSON.stringify(userMessageList);
            $("#list-contact").append(`
${user.fullname}پیام جدیدی وجود ندارد
`); counter++; } getUserUnreadMessages(); setInterval(getUserUnreadMessages, 2500); } function getDataChat(query, cbk, loop = false) { const queryString = jQuery.param(query); $.ajax({ type: "head", url: httpURL + "/process.php", data: queryString, dataType: "json", complete: function(e) { if (200 <= e.status < 300) { $.get({ url: httpURL + "/process.php", data: queryString, dataType: "json", success: cbk, complete: function(e) { if (loop) setTimeout(getDataChat, 2000, query, cbk, loop); } }); } else { if (loop) setTimeout(getDataChat, 2000, query, cbk, loop); } } }); } // *********** dom event *********** $(document).on("click", ".contact-box", contactHandler); function contactHandler(e) { const thisElement = $(this); const sendToUser = thisElement.data("username"); $('.contact-box').removeClass("active"); thisElement.addClass("active"); if (sendToUser !== undefined) { oldLength = -1; keypadWrapperDOM.removeClass("ds-none"); sendToDOM.val(sendToUser); helperMessageViewDynamicContent(); } } function sendMessageBtnHandler() { const thisElement = $(this); const message = keypadDom.val(); const sendToUser = sendToDOM.val() if (message != "" && sendToUser != "") { getDataChat({ state: "snd_msg", to_user: sendToUser, msg: message }, addNewOwnMessageToMessageView, false); } } function generateMessageBox(messageDetails) { messageViewDOM.append(`
${messageDetails.content} ${messageDetails.time}
`); } });


فایل process.php مدیریت سمت سرور با PHP

در ابتدا کوکی کاربر را اعتبارسنجی می کنیم که آیا امکان دسترسی دارد یا خیر .

به طور کلی سمت سرور را با استفاده از Query String کنترل می کنیم :

state برای دریافت نوع ارسال داده ها است اگر باشد :
rcv_msg پیام های کاربر را دریافت می کند
rcv_msg_unread یعنی کاربر قرار است پیام های خوانده نشده را دریافت کند
snd_msg یعنی کاربر پیامی را می خواهد ارسال کند
snd_msg_state زمانی که کاربر پیام را خواند آن را بروزرسانی کند به خوانده شده
rcv_usr برای لیست کردن تمامی کاربران در چت روم

header("Content-Type: application/json");

if (!empty($_COOKIE['username'])) {

	require_once "define.php";
	require_once ABSPATH . "inc" . DSPR . "class-loader.php";
	$db = new DB();
	$uname = $_COOKIE['username'];

	$get_data = $_GET;
	$state = !empty($get_data["state"]) ? $get_data["state"] : "";
	$from_user = !empty($get_data["from"]) ? $get_data["from"] : "";

	if ($state == "rcv_msg" && !empty($from_user)) {

		$all_msg_unique = !empty($get_data["all_msg_unique"]) ? $get_data["all_msg_unique"] : "";

		if ($all_msg_unique === "true") {
			$user_messages = $db->row_select(['table' => 'message_repo', 'content' => "((`to_usr`=? AND `from_usr`=?) OR (`to_usr`=? AND `from_usr`=?)) ORDER BY `id` ASC", "types" => "ssss", "values" => [$uname, $from_user, $from_user, $uname]]);
		} else {

			$user_messages = $db->row_select(['table' => 'message_repo', 'content' => "`to_usr`=? AND `from_usr`=? AND `seen`=? ORDER BY `id` ASC", "types" => "sss", "values" => [$uname, $from_user, 0]]);
		}

		if (!$user_messages) {

			header("HTTP/1.0 304 Not Modified", true);
		}

		if (!empty($get_data['count']) && $get_data['count'] === "true") {
			$sanitized_messages = ["countMessage" => count($user_messages), "from_user" => $from_user];
		} else {
			$sanitized_messages = [];
			foreach ($user_messages as $user_message) {
				$sanitized_messages[] = [
					'unique_user' => $from_user,
					'from_user' => $user_message['from_usr'],
					'from_user_fullname' => $user_message['from_usr_name'],
					'to_user' => $user_message['to_usr'],
					'message' => $user_message['message'],
					'timestamp_sent' => $user_message['timestamp_sent'],
				];
			}

		}

		echo json_encode($sanitized_messages);

	} elseif ($state == "rcv_msg_unread") {

		$user_messages = $db->row_select(['table' => 'message_repo', 'content' => "`to_usr`=? AND `seen`=? ORDER BY `id` ASC", "types" => "ss", "values" => [$uname, 0]]);

		if (!$user_messages) {

			header("HTTP/1.0 304 Not Modified", true);
		}

		if (!empty($get_data['count']) && $get_data['count'] === "true") {
			$sanitized_messages = ["countMessage" => count($user_messages), "from_user" => $from_user];
		} else {
			$sanitized_messages = [];
			foreach ($user_messages as $user_message) {
				$sanitized_messages[] = [
					'unique_user' => $user_message['from_usr'],
					'from_user' => $user_message['from_usr'],
					'from_user_fullname' => $user_message['from_usr_name'],
					'to_user' => $user_message['to_usr'],
					'message' => $user_message['message'],
					'timestamp_sent' => $user_message['timestamp_sent'],
				];
			}

		}

		echo json_encode($sanitized_messages);

	} else if ($state == "snd_msg" && $_SERVER['REQUEST_METHOD'] != "HEAD") {
		if (isset($get_data['to_user']) && $get_data['to_user'] !== $uname && isset($get_data['msg'])) {
			$user_exist = $db->row_exist(['table' => 'users', 'content' => "username=?", "types" => "s", "values" => [$get_data['to_user']]]);
			if ($user_exist) {
				$time = time();
				Helper::verify_user_by_session();
				$user_fullname = $GLOBALS['current_user']['fullname'];
				$res = $db->row_insert([
					'table' => 'message_repo',
					'content' => "(`from_usr`, `from_usr_name` , `to_usr` , `message` , `timestamp_sent` , `timestamp_seen`) VALUES (? , ? , ? , ? , ? , ?)",
					"types" => "ssssss",
					"values" => [$uname, $user_fullname, $get_data['to_user'], $get_data['msg'], $time, '0'],
				]);

				echo "{\"time_sent\":\"{$time}\",\"msg\" : \"success\",\"status\" : \"1\"}";

				header("HTTP/1.0 201 Created", true);

			} else {
				header("HTTP/1.0 304 Not Modified", true);
			}

		} else {
			echo '{"msg" : "require complete data" , "status" : "0"}';
		}

	} else if ($state === "snd_msg_state") {
		if (isset($get_data['from_user']) && $get_data['from_user'] !== $uname) {
			$time = time();
			$res = $db->row_update(["table" => "message_repo", "content" => "`seen`=? , `timestamp_seen`=? WHERE `to_usr`=? AND `from_usr`=?", "types" => "ssss", "values" => [1, $time, $uname, $get_data['from_user']]]);

			if ($res) {
				echo "{\"time_sent\":\"{$time}\",\"user_room\" : \"{$get_data['from_user']}\",\"msg\" : \"success\",\"status\" : \"1\"}";
			}

		} else {
			header("HTTP/1.0 304 Not Modified", true);
		}

	} else if ($state === "rcv_usr") {
		$users = $db->row_select(['table' => 'users', 'content' => "`username` != ? AND `verified`=?", "types" => "ss", "values" => [$uname, 1]]);

		if (!$users) {
			header("HTTP/1.0 304 Not Modified", true);
		}

		$sanitized_users = [];
		foreach ($users as $user) {
			$sanitized_messages[] = [
				'username' => $user['username'],
				'fullname' => $user['fullname'],
			];
		}

		echo json_encode($sanitized_messages);
	}

}


دموی پروژه ساخت چت روم با PHP و jQuery

پروژه ساخت چت روم با PHP و jQuery
پروژه چت روم با PHP و jQuery


قبل از اجرای برنامه وارد پوشه chatroom DATABASE to import شده دیتابیس را import کنید


دانلود پروژه ساخت چت روم با PHP و jQuery

ارسال نظر

جهت استفاده از کد حتما از تگ pre استفاده نمایید .

لیست نظرات

  1. پرهام ناصحی
    پرهام ناصحی

    معنی این ارور چیست ؟ Fatal error: Uncaught Error: mysqli_stmt object is not fully initialized in D:\xampp\htdocs\chatroom\inc\class-DB.php:24 Stack trace: #0 D:\xampp\htdocs\chatroom\inc\class-DB.php(24): mysqli_stmt->close() #1 [internal function]: DB->__destruct() #2 {main} thrown in D:\xampp\htdocs\chatroom\inc\class-DB.php on line 24

    07 اسفند 1400 | 15:50:56
  • حسین باقری
    حسین باقری

    فکر می کنم موقعیت stmt رو تغییر داده باشید یا close اون stmt رو تغییر دادین

    07 اسفند 1400 | 18:10:18
    • پرهام ناصحی
      پرهام ناصحی

      من PDO کار میکنم . چطور درستش کنم ؟

      07 اسفند 1400 | 18:50:36
      • حسین باقری
        حسین باقری

        می تونید از این داکیومنت استفاده کنید .

        07 اسفند 1400 | 19:31:02
  • پرهام ناصحی
    پرهام ناصحی

    ببخشید شما دوره هاتون هم همین قدر حرفه ایه ؟

    07 اسفند 1400 | 15:34:11
    • حسین باقری
      حسین باقری

      درود فعلا در حال ضبظ هستیم و منتشر نشده توی دوره مون سعی می کنیم بالاترین کیفیت رو به هنرجو انتقال بدیم .

      07 اسفند 1400 | 18:08:12
  • محمد مهدی شجاعیان
    محمد مهدی شجاعیان

    سلام خوبید میتونید بگید چجوری دیتابیس رو ایمپورت کنم من دیتابیس رو ساختم ولی نمیتونم ایمپورتش کنم ترو خدا کمکم کنید

    28 فروردین 1400 | 21:14:36
    • حسین باقری
      حسین باقری

      درود شما نیازی نیست که دیتابیسی بسازید فقط کافیه که دیتابیس chatroom.sql رو import کنید .

      27 اردیبهشت 1400 | 17:03:01
  • حمید رضا
    حمید رضا

    سلام ببخشید در هنگام راه اندازی سورس ها در برنامه ومپ سرور به کد خطای زیر مواجه شدم میشه راه نمایی بفرمایید

    14 اسفند 1399 | 11:46:40
    • حمید رضا
      حمید رضا

      Parse error: syntax error, unexpected ',', expecting ')' in C:\wamp\www\chatroom-php-jquery\inc\class-DB.php on line 12 این کد بوده

      14 اسفند 1399 | 11:47:51
      • حسین باقری
        حسین باقری

        درود خطای سینتکسی احتمالا پرانتز اضافه یا کاما یا سیمیکالن نذاشتید

        16 اسفند 1399 | 19:35:26
  • نیما خسروی
    نیما خسروی

    سلام اگه میشه آموزش ویدیویی رو هم بزارید.

    29 دی 1399 | 21:50:49
    • حسین باقری
      حسین باقری

      درود ، حتما

      06 اسفند 1399 | 16:38:30
  • دهکده من
    دهکده من

    سلام اگر می خواهیم آدرس localhost/chat باز کنیم به مشکل می خوریم چه کنیم

    16 آبان 1399 | 16:04:06
    • حسین باقری
      حسین باقری

      فایل ها را وارد پوشه ای به نام chat کنید .

      13 آذر 1399 | 18:22:56
    contact us