ساخت نوتیفیکیشن با php و Ajax ( اطلاع رسانی کاربران )

ساخت نوتیفیکیشن با php – خیلی از مواقع در فیسبوک شاهد این بوده ایم که رویداد های مختلفی را با استفاده از زنگوله بالا سمت راست متوجه شده ایم و کاربران را اطلاع رسانی کرده است .
در این آموزش همان زنگوله را قرار هست که نمونه آن را بسازیم آن هم به صورت AJAX .
این آموزش شامل 6 فایل می باشد برای ساخت برنامه نوتیفیکیشن با php :
- اسکریپت index.php : صفحه نمایش نوتیفیکیشن ها
- اسکریپت notify.php : این صفحه معمولا در صفحه ادمین می باشد که 2 فیلد پیام و لینک را دریافت و به کاربر ارسال می کند
- اسکریپت db.php : همان طور که از اسمش پیداست برای تعامل با دیتابیس به کارمان می آید
- اسکریپت api.php : از آنجایی که قرار است درخواست های ajax بفرستیم نیازمند یک آدرس استاندارد شده برای ارسال و دریافت اطلاعات آن هم به صورت json هستیم که با دیتابیس اطلاعات ذخیره و خوانده شود
- اسکریپت app.js : درخواست های http و رویداد و رفتار های برنامه را با این اسکریپت javascript کنترل می کنیم .
- استایل main.css : برای زیبایی برنامه مان و رعایت چیدمان المان های html
دموی برنامه ساخت نوتیفیکیشن با PHP
1- اسکریپت index.php
<!DOCTYPE html> <html lang="fa"> <head> <meta charset="UTF-8"> <title>Rapidcode.iR - سورس کد</title> <link rel="stylesheet" href="static/css/main.css"> </head> <body style="height: 3000px"> <div class="container"> <h1>رپید کد</h1> <header id="menu-1" class="menu"> <nav> <ul> <li><a href="https://rapidcode.ir">رپید کد </a></li> <li><a href="#">صفحه 1</a></li> <li><a href="#">صفحه 2</a></li> <li><a href="#">صفحه 3</a></li> <li><a href="#">صفحه 4</a></li> <li><a href="#">صفحه 5</a></li> <div class="notification-wrapper"> <div class="notification-bell"></div> <div class="notification-num">0</div> <div class="notification-messages"> <span class="arrow"></span> <ul class=""></ul> </div> </div> <div class="clearfix"></div> </ul> </nav> </header> </div> <script src="static/js/app.js"></script> </body> </html>
2- اسکریپت notify.php
<!DOCTYPE html> <html lang="fa"> <head> <meta charset="UTF-8"> <title>Rapidcode.iR - سورس کد</title> <link rel="stylesheet" href="static/css/main.css"> </head> <body> <div class="container"> <h1>رپید کد</h1> <form id="form-wrapper"> <textarea name="notify-message" id="notify-message" cols="30" rows="10" placeholder="پیام"></textarea> <input name="notify-link" id="notify-link" type="text" dir="ltr" placeholder="لینک"> <input id="notify-send" type="button" value="ارسال"> </form> </div> <script src="static/js/app.js"></script> </body> </html>
3- اسکریپت db.php
<?php $mysqli = new mysqli("localhost", "root", "", "cms"); if ($mysqli->connect_error) { die("MYSQL ISSUE : " . $mysqli->connect_error); } $mysqli->set_charset("utf8"); $stmt = $mysqli->stmt_init(); function getData($uquery,$data=[]){ global $mysqli; global $stmt; $query = $uquery; $rows = []; $stmt->prepare($query); if(sizeof($data)) $stmt->bind_param(str_repeat("s",count($data)), ...$data); if ($stmt->execute() && $res = $stmt->get_result()) { if ($stmt->affected_rows || $res->num_rows) { while ($row = $res->fetch_assoc()) { $rows[] = $row; } } } return $rows; } function setData($uquery , $data){ global $mysqli; global $stmt; $query = $uquery; $stmt->prepare($query); $type = str_repeat("s",count($data)); $stmt->bind_param($type, ...$data); $inserted_id=0; if ($stmt->execute()) { $inserted_id = $stmt->affected_rows ? $stmt->insert_id : 0; } return $inserted_id; } function check_posted_data($posted_data , $list_post_keys){ $is_valid_posted_data = array_map(function($name){ global $posted_data; return in_array($name , array_keys($posted_data)) && !empty($posted_data[$name]); }, $list_post_keys); return in_array(false,$is_valid_posted_data); } ?>
4- اسکریپت api.php
<?php header("Content-Type: application/json"); $action = @$_GET['action']; $valid_actions = ['snd' , 'rcv']; if(!in_array($action, $valid_actions)){ die('{"msg" : "action نامعتبر", "status" : 0}'); } require_once "db.php"; $posted_data = @$_POST; $posted_data_name_list = [ "snd" => ['notify-message' , 'notify-link'], "rcv" => ['offset'], ]; $posted_data_name = $posted_data_name_list[$action]; $is_false = check_posted_data($posted_data , $posted_data_name); if($is_false) die('{"msg" : "فیلد های اجباری وارد نشده است", "status" : 0}'); if($action == "snd"){ $tmp_posted_data = [ $posted_data['notify-message'], $posted_data['notify-link'], date("Y/m/d") ]; $res = setData("INSERT INTO `notification` (`message` , `link` , `created_at`) VALUES (? , ? , ?)" , $tmp_posted_data); if($res) die('{"msg" : "با موفقیت ذخیره شد" , "status" : 1}'); else die('{"msg" : "خطایی در هنگام ذخیره اطلاعات رخ داده" , "status" : 0}'); }else if($action == "rcv"){ $special_statement = [ 'all' => 'SELECT * FROM `notification`', 'limit' => 'SELECT * FROM `notification` ORDER BY id DESC LIMIT 1' ]; $offset = @$special_statement[$posted_data['offset']]; if(!$offset) $offset = $special_statement['all']; $rows = getData($offset , []); $response_list = ['message' => 'اطلاعات با موفقیت از دیتابیس بارگذاری شد', 'status' => 1 , 'data' => []]; foreach ($rows as $row) { array_push($response_list['data'], $row); } die(json_encode($response_list)); } ?>
5- اسکریپت app.js
// DOM const notifyFormDOM = document.getElementById('form-wrapper'); const notifyMessageDOM = document.getElementById('notify-message'); const notifyLinkDOM = document.getElementById('notify-link'); const notifySendDOM = document.getElementById('notify-send'); const messagesNumDOM = document.getElementsByClassName('notification-num')[0]; const messagesBellDOM = document.getElementsByClassName('notification-bell')[0]; const messagesMessagesDOM = document.getElementsByClassName('notification-messages')[0]; if (messagesMessagesDOM) { var messagesMessagesUlDOM = messagesMessagesDOM.querySelector('ul'); var messagesArrowDOM = messagesMessagesDOM.querySelector('.arrow'); } // property const lastNotificationID = 0; if (messagesMessagesDOM) { setTimeout(function() { window.scrollTo(0, 105) }, 100) var audio = new Audio("static/audio/recive.mp3"); } // set handlers if (notifySendDOM) notifySendDOM.onclick = notifySendDOMClicked; if (messagesMessagesDOM) { messagesBellDOM.onclick = messagesBellDOMClicked; checkMessageEvery5Sec(); } // handlers function notifySendDOMClicked() { if (notifyMessageDOM.value == "" || notifyLinkDOM.value == "") { alert("لطفا هر دو فیلد را پر کنید"); return false; } notifySendDOM.setAttribute("disabled", "disabled"); const params = new FormData(notifyFormDOM); initXHR({ method: "POST", action: "snd", onload: function() { const response = this.response; const message = response.msg; const status = response.status; if (status == 1) { alert(message); } else { alert(message); console.error(message); } notifySendDOM.removeAttribute("disabled"); }, onerror: function() { console.warn("XHR ERROR") notifySendDOM.removeAttribute("disabled"); }, data: params }); } function messagesBellDOMClicked() { messagesMessagesUlDOM.classList.toggle("active"); messagesArrowDOM.classList.toggle("active"); checkMessageListOpen(); } // helpers function initXHR(config) { const xhr = new XMLHttpRequest(); xhr.responseType = "json"; xhr.open(config['method'], "http://localhost/app/api.php?action=" + config['action']); xhr.onload = config['onload']; xhr.onerror = config['onerror']; xhr.send(config['data']); } function checkMessageEvery5Sec() { setTimeout(function() { const lastIdHTML = getNotificationLastHtmlID(); const params = new FormData(); let offset = "limit"; if (lastIdHTML == false) { offset = 'all'; } params.append("offset", offset); initXHR({ method: "POST", action: "rcv", onload: function() { const response = this.response; const data = response.data; checkMessageEvery5Sec(); if (data.length == 0 || data[data.length - 1]['id'] == lastIdHTML) { return false; } data.forEach(function(dta) { const html = generateLiHtml(dta); messagesMessagesUlDOM.innerHTML += html; }); if (!localStorage.getItem('notificationLastID')) changeNotificationNumbersContent(messagesMessagesUlDOM.querySelectorAll("li").length); else { changeNotificationNumbersContent(checkUnreadMessageNumbers(data)); } }, onerror: function() { console.warn("XHR ERROR") alert('خطایی در ارتباط با دیتابیس پیش آمده'); }, data: params, }); }, 5000) } function generateLiHtml(data) { data['created_at'] = new Intl.DateTimeFormat('fa-IR').format(new Date(data['created_at'])); const html = `<li id="li-${data['id']}" data-id="${data['id']}"><small id="date">${data['created_at']}</small><p id="message">${data['message']}</p><a href="${data['link']}" id="more">مشاهده</a></li>`; return html; } function getNotificationLastHtmlID() { const allLiDOM = messagesMessagesUlDOM.querySelectorAll("li"); if (allLiDOM.length == 0) return false; const lastLiDOM = allLiDOM[allLiDOM.length - 1]; const lastId = lastLiDOM.getAttribute("data-id"); return lastId; } function checkMessageListOpen() { if (messagesMessagesUlDOM.classList.contains("active")) { localStorage.setItem('notificationLastID', getNotificationLastHtmlID()); changeNotificationNumbersContent(checkUnreadMessageNumbers([])) } } function checkUnreadMessageNumbers(data) { let unreadMessagesNumber = 0; data.forEach(function(dta) { const id = dta['id']; const liDOM = document.getElementById('li-' + id); if (liDOM) { const elementID = liDOM.dataset.id; if (parseInt(localStorage.getItem('notificationLastID')) < parseInt(elementID)) liDOM.setAttribute('data-unread', 'true'); } }); unreadMessagesNumber = document.querySelectorAll('li[data-unread]').length; if (0 < unreadMessagesNumber && messagesMessagesUlDOM.classList.contains("active")) { localStorage.setItem('notificationLastID', getNotificationLastHtmlID()); markReadedLi(); unreadMessagesNumber = document.querySelectorAll('li[data-unread]').length; audio.play(); } else if (0 < unreadMessagesNumber && !messagesMessagesUlDOM.classList.contains("active")) { audio.play(); } return unreadMessagesNumber; } function markReadedLi() { const readedDOM = document.querySelectorAll('li[data-unread]'); readedDOM.forEach(function(element) { element.removeAttribute('data-unread'); }); } function changeNotificationNumbersContent(number) { messagesNumDOM.innerHTML = number; if (messagesNumDOM.innerHTML != 0) { audio.play(); } }
6- استایل main.css
.container { margin: 0 auto; width: 80%; text-align: center; direction: rtl; } /* Page Style */ body { margin: 0 !important; } .clearfix { clear: both; } #menu-1 { background-color: #607d8b; border-bottom: 6px dotted transparent; transition: 0.3s all; } #menu-1 ul { list-style: none; padding: 0; margin: 0; } #menu-1 ul li { float: right; } #menu-1 ul li a { text-decoration: none; display: block; color: white; font-weight: bold; padding: 15px; margin-left: 25px; } .active { display: block !important; } .notification-wrapper { float: left; position: relative; z-index: 100; } .notification-bell { background-image: url("../img/bell.svg"); width: 30px; height: 30px; margin: 12px 0 0 12px; cursor: pointer; } .notification-num { display: block; position: absolute; top: 4px; right: -23px; width: 17px; height: 17px; color: #1a1a1a; text-align: center; border: 2px solid #ff562b; background-color: #ffbe11; border-radius: 50%; padding: 2px; } .notification-messages { position: relative; } .notification-messages ul { position: absolute; top: 17px; left: -40px; background-color: #ffffff; box-shadow: 0 0 5px #d4d4d4; width: 300px; height: 400px; border-radius: 4px; overflow-y: auto; overflow-x: hidden; display: none; z-index: -3; } .arrow { border-left: 10px solid transparent; border-right: 10px solid transparent; border-bottom: 10px solid #ffffff; position: absolute; left: 17px; top: 7px; display: none; } .notification-messages ul li { padding: 5px; border-bottom: 1px solid #f2f2f2; width: 100%; } .notification-messages ul li small { color: #b7b7b7; display: block; text-align: right; } .notification-messages ul li p { font-weight: bold; color: #757575; text-align: right; } .notification-messages>ul>li>a#more { text-decoration: none; color: #00bcd4; display: inline-block; padding: 5px; margin: 0; } /* notify */ #notify-message, #notify-link { resize: none; width: 100%; border: 1px solid #2196f3; padding: 5px; font-size: large; outline: none; margin-bottom: 25px; } #notify-send { background-color: #2196f3; border: none; outline: none; padding: 10px 35px; font-weight: bold; color: white; font-size: 15px; border-radius: 6px; cursor: pointer; } #notify-send:disabled { opacity: 0.5; }
قبل از اجرای برنامه وارد پوشه database شده و فایل cms.sql را import کنید .
ارسال نظر