Sử dụng SSE trong PHP

Sử dụng SSE trong PHP là sử dụng kỹ thuật SSE để đưa dữ liệu về user 1 cách tự động khi có dữ liệu mới từ phía server, code phía server sẽ dùng là PHP nhé.

1.  Kiến thức cần biết để sử dụng SSE trong PHP

a. Code phía server

  • Khi cho phía server, kết quả bạn cần đổ về cho client phải là 1 khối text gồm nhiều dòng chữ. Dòng bắt đầu bằng chữ id là id của sự kiện (giống như mã định danh). Dòng bắt đầu bằng chữ retry là thời khoản (số miligiây) để browser lên lại server lấy tiếp thông tin. Dòng bắt đầu bằng chữ data là dữ liệu chính đổ về cho browser.  Mỗi dòng text kết thúc bằng \n riêng dòng cuối kết thúc bằng \n\n
  • Code phía server: bạn phải có dòng lệnh không cho browser cache nhé, kẻo nó không request lên server là gay.
  • Code phía server cần báo cho browser kiểu dữ liệu đổ về là text/event-tream

b. Code phía client

  • Code phía client là code javascript để đón dữ liệu từ server và hiện ra trong nội dung trang.
  • Client (tức browser) sẽ nhìn vào giá trị của biến retry đổ về từ server để biết thời khoảng request lại server để lấy dữ liệu.
  • Code ở phía client có thể lấy id của sự kiện và nội dung data đổ về tử server theo cú pháp event.lastEventId  và event.data

2. Chuẩn bị trước khi thử sử dụng sse trong php

Việc chuẩn bị bao gồm tạo folder website tạo database, tạo table và chèn dữ liệu vào table. Sau đó chúng ta mới đến mục tiêu chính ở phía sau là sử dụng sse trong php.

a. Tạo folder

Trong htdocs, tạo folder sse để thực tập thử. Chút nữa các file tạo ra sẽ đặt trong đây nhé.

b.  Tạo database và table

  • Bạn vào phpMyadmin và tạo datavase có tên là news, nếu có rồi thì khỏi tạo nữa.
  • Tiếp tục, trong database news, bạn tạo table tuongthuat như sau
CREATE TABLE `tuongthuat` (
  `id` bigint(20) NOT NULL,
  `phut` varchar(10) NOT NULL,
  `noidung` varchar(2000) NOT NULL,
  `thoidiem` timestamp NOT NULL DEFAULT current_timestamp()
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
ALTER TABLE `tuongthuat` ADD PRIMARY KEY (`id`);
ALTER TABLE `tuongthuat` MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT;

c.  Chèn dữ liệu vào db

  • Tạo file sse\chentuongthuat.php
  • Code trong file vừa tạo:
<html><head><meta charset="utf-8">
<link rel="stylesheet" href= "https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" >
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" ></script>
<script src= "https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"> </script>
<script src= "https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"> </script></head><body>
<div class="container">
<form class="form-horizontal col-8 bg-secondary mt-5 mx-auto text-warning font-weight-bold p-3" method="post">
    <div class="form-group">
      <label for="phut">Phút:</label>
      <input class="form-control border-warning" id="phut" name="phut" autofocus>
    </div>
    <div class="form-group">
      <label for="nd">Nội dung:</label>
      <textarea  class="form-control border-warning" id="nd" name="nd" rows="5"></textarea>
    </div>
    <button type="submit" class="btn btn-default text-primary font-weight-bold border-warning "> LƯU </button>
</form>
</div></body> </html>
chèn tường thuật

Như vậy, chúng ta mới tạo xong form để chèn dữ liệu, bây giờ nhắp nút Lưu cũng chưa có tác dụng gì đâu, code tiếp nhe.

  • Ở đầu trang, code để lưu dữ liệu vào table tuongthuat
<?php
session_start();
if (isset($_POST)){
    $phut= trim($_POST['phut']);
    $noidung= trim($_POST['nd']);
    if ($phut !="" && $noidung!=""){
        $db= new mysqli ("localhost","root","","news");  
        $db->set_charset("utf8");
        $sql="INSERT INTO tuongthuat SET phut='$phut', noidung='$noidung'";
        $kq = $db->query($sql);
        $_SESSION['thongbao']= "Đã lưu. <br>Phút=$phut <br>ND: $noidung ";
        header("location:chentuongthuat.php");
        exit();
    }
}
?>
  • Code trên giúp lưu dữ liệu vào db rồi đó, nhưng khoan test, bạn cần hiện thông báo rồi test nhé. Đoạn code sau viết ngay sau mở đầu của tag form (trước tag <div class=”form-group”>), mục đích là để hiện thông báo đã lưu thông tin vào db xong.
<?php if (isset($_SESSION['thongbao'])) {
   echo "<div class='alert alert-success mt=3'> {$_SESSION['thongbao']} </div>";
   unset($_SESSION['thongbao']);
} ?>
sse chèn tường thuật bóng đá

Khê khê khê, xong bước chuẩn bị. Bây giờ thì chúng ta thử nghiệm SSE chơi.

3. Sử dụng SSE trong PHP để xem giờ trên server

Chúng ta sẽ bắt đầu dùng SSE với ứng dụng thật đơn giản trước nhé: đổ giờ từ server về và hiện ra trong 1 chỗ nào đó trong trang, mục đích để phía client luôn có thời gian chính xác do server cung cấp.

a.  Code phía server

Code phía server là code chạy trên server để cung cấp dữ liệu cho phía client.

  • Tạo file sse\gio.php
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
$time = gmdate('d/m/Y H:i:s', time() + 3600*7 );
echo "id: 1\n";
echo "retry: 500\n";
echo "data: {$time}\n\n";
flush();
?>
sse xem giờ server

b.     Code phía client (browser)

Code phía cluent là code javascript để đón dữ liệu từ server.

  • Tạo file sse\xemgio.php
<html><body>
<div>Bây giờ là <span id="kq"></span> </div>
<script>
if(typeof(EventSource)!== "undefined") {
  var url= "http://localhost/sse/gio.php";
  var source = new EventSource(url);
  source.onmessage = function(event) {
    document.getElementById("kq").innerHTML = event.data;
  };
} else document.getElementById("kq").innerHTML = "Browser không hỗ trợ";
</script>
</body></html>
  • Test: http://localhost/sse/xemgio.php , bạn sẽ thấy giờ liên tục thay đổi vì cứ 500 mili giây thì trình duyệt request lại server để lấy dữ liệu.
sse xem giờ server

Ghi chú: Bạn có thể phát triển thêm:  thay vì lấy giờ thì lấy các thông tin hệ thống như tình trạng cpu, mem … để theo dõi trạng thái server

4. Sử dụng SSE trong PHP đổ vể dữ liệu từ db (tường thuật bóng đá)

Ví dụ này sẽ thực hiện thử nghiệm như sau: Admin vừa chèn dữ liệu vào database, ngay lập tức thông tin vừa chèn trong database đó sẽ hiện tự động trên client. User chẳng cần làm gì.

a. Code phía server

– Tạo sse\dienbien.php và code:

<?php
$db = new mysqli("localhost","root","", "news");
$db->set_charset("utf8");
$kq = $db->query( "select phut, noidung from tuongthuat order by id DESC LIMIT 0,1");
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
if ($kq->num_rows > 0) {
    $row = $kq->fetch_assoc();
    echo "id: ", $row['phut'], "\n";
    echo "retry: 5000\n";
    echo "data: <p>Phút ", $row['phut'], "</p> \n";
    echo "data: <div>",nl2br($row['noidung'])."</div><hr>\n\n";
}
flush();
?>

– Test file http://localhost/sse/dienbien.php

sse - diễn biến bóng đá

b.  Code phía client

Code phía cluent là code javascript để đón dữ liệu từ server.

  • Tạo file sse\tuongthuat.php và code
<html><body>
<h1>Tường thuật bóng đá</h1>
<div id="kq"></div>
<script>
if(typeof(EventSource) !== "undefined") {
  var url= "http://localhost/sse/dienbien.php";
  var id=0; //biến này để lưu id của event
  var source = new EventSource(url);
  source.onmessage = function(event) {
    if (event.lastEventId!=id){  //nếu id lần này và lần trước khác nhau thì mới hiện
      id = event.lastEventId; //mỗi lần dữ liệu về là lưu vào biến id
      document.getElementById("kq").innerHTML +=  event.data + "<br>";     
    } //if
  };
} else document.getElementById("kq").innerHTML = "Browser không hỗ trợ";
</script>
</body></html>
sse xem tường thuật bóng đá

c. Test thử nhé

Mở 3 cửa sổ trình duyệt sắp xếp cho thấy hết nhé, trình duyệt 1 và 2: bạn xem file tuongthuat.php (đóng vai 2 người xem hé). Trình duyệt 3 bạn xem file chentuongthuat.php (đóng vai admin) . Xem hình dưới.

sse xem tường thuật bóng đá

Nhập thông tin vào form như hình rồi nhắp nút Lưu, bạn sẽ thấy thông tin mới trên màn hình 2 người xem (như hình dưới)

sse xem tường thuật bóng đá

Tương tự, bạn tiếp tục tường thuật thêm nhé: phút 12, 16, cho đến phút 90, lấy dữ liệu gợi ý trong bảng bên dưới.

1 Trận đấu bắt đầu.
6 Rabo Ali thực hiện đường chuyền từ sân nhà. Wander Luiz bật cao đánh đầu nhưng bóng đi không trúng đích. Chủ nhà Bình Dương chủ động chơi bóng dài trong điều kiện mặt sân trơn trượt.
12 Từ chấm đá phạt bên cánh trái, Minh Vương thực hiện cú đá đưa bóng hướng vào góc xa khung thành Bình Dương nhưng thủ môn Tấn Trường đã chơi cảnh giác.
16 NGUY HIỂM! Từ pha căng ngang của Châu Ngọc Quang, Shumeiko lóng ngóng chạm bóng nhưng Tấn Trường đã kịp phản xạ cứu thua cho chủ nhà Bình Dương.
18 Mặt sân sũng nước khiến HAGL không thể triển khai lối chơi ban bật sở trường. Đoàn quân của HLV Lee Tae-hoon dồn bóng ra cánh rồi thực hiện những pha căng ngang và suýt chút nữa đã có bàn mở tỷ số.
23 Điều kiện sân bãi không tốt hạn chế lối chơi của các cầu thủ HAGL, đặc biệt là mẫu tiền đạo tốc độ như Văn Toàn. Không có chân sút ngoại Felipe trên sân, những tình huống bóng bổng của đội khách khá vô hại. 
26 CƠ HỘI! Nhận đường chuyền của Ngọc Quang, V.Toàn tung cú sút xa nhưng không gây khó khăn cho Tấn Trường
32 Chủ nhà Bình Dương liên tục thực hiện những tình huống treo bóng vào vùng cấm HAGL. Sau thủ môn Văn Trường, đến lượt Kim Bong Jin bị đau sau những nỗ lực tranh chấp trên không.
35 KHÔNG VÀO!! Trọng Huy tung cú sút xa đưa bóng đi chệch khung thành đội khách trong gang tấc.
36  KHÔNG VÀO!! Tình huống phá bóng Trọng Sáng (HAGL) trở thành cú dứt điểm hiểm hóc về phía khung thành của Tấn Trường. Rất may khi bóng đi chệch cột.
38 Tuấn Anh nhận thẻ vàng vì ngăn cản tình huống phản công của chủ nhà.
41 Không có quá nhiều cơ hội được 2 đội tạo ra. Thủ môn Tấn Trường thi đấu khá ổn định từ đầu trận đấu
45 45 phút đầu tiên trôi qua mà không có bàn thắng nào được ghi. Cơ hội của 2 đội hầu hết đến từ những tình huống treo bóng vào vùng cấm hoặc sút xa
55 VÀO!! Từ pha đá phạt bên cánh trái, Tiến Linh thoải mái băng vào đánh đầu cận thành không cho Văn Trường cơ hội cản phá.
60 Văn Thanh ngã trong vùng cấm chủ nhà nhưng không có tiếng còi từ trọng tài chính. Cầu thủ số 17 dành phần lớn thời gian để phòng ngự và chưa có nhiều đóng góp cho mặt trận tấn công của HAGL.
64 HAGL được hưởng quả đá phạt từ khá xa, Văn Thanh tự tin tung cú đá thẳng nhưng bóng đi không trúng đích.
66 KHÔNG ĐƯỢC! Tiến Linh có pha khống chế gọn gàng trong vùng cấm. Nhưng ở tình huống bắt volley, tiền đạo đội chủ nhà lại không sút trúng tâm bóng.
68 VÀO!! Nhận đường chuyền của Tô Văn Vũ, Sỹ Giáp xoay người dứt điểm hạ gục Văn Trường. Xem lại pha quay chậm, số 27 của chủ nhà đã việt vị nhưng bàn thắng vẫn được công nhận
69 Xuân Trường vào sân thay Minh Vương
70 KHÔNG VÀO!! Tấn Trường có tình huống cứu thua xuất sắc cú sút của Văn Toàn. Thủ môn đội chủ nhà đã bị đau
76 Tấn Trường lại nằm sân và phải nhờ đến sự trợ giúp của bác sĩ. Thủ môn của Bình Dương có lẽ đã bị ảnh hưởng sau khi bị Văn Toàn sút trúng mặt.
79 Hàng công còn chưa tìm được bàn thắng, sự lơ là của hàng phòng ngự đã khiến HAGL thủng lưới đến 2 lần. Với thế trận bế tắc này, cơ hội để Văn Toàn cùng đồng đội giành điểm trước chủ nhà là rất nhỏ
80 KHÔNG ĐƯỢC! Xuân Trường tung cú sút xa khó chịu, bóng đập đất nhưng Tấn Trường vẫn làm chủ tình hình.
87 VÀO!! Tiến Linh lại ghi tên lên bảng tỷ số. Chân sút số 22 thoải mái thoát xuống đón đường chuyền của Lê Tấn Tài. Anh xoay người loại bỏ hậu vệ rồi dứt điểm hạ gục nốt thủ môn Văn Trường.
90 Trận đấu khép lại với thắng lợi 3-0 cho chủ nhà Bình Dương