Hiệu ứng facebook notification trong PHP

Chào các bạn, hôm nay mình giới thiệu với các bạn cách tạo hiệu ứng tự động thông báo của facebook khi có một tin nhắn mới trong php và ajax. Đây là một chủ đề mà lâu nay mình cũng thắc mắc rất nhiều, dù không biết cơ chế của facebook làm việc như thế nào với cái notification, mình cũng đưa ra để mọi người tham khảo cũng như trao đổi thêm. Link download toàn bộ tutorial này

Không dài dòng nữa, sau đây là nội dung bài viết:
Sơ lược mô hình về bài hiệu ứng notification trong php như sau:

  1. Cấu trúc cây thư mục:
  2. Các table đã tạo trong database:

  3. Lớp database.php:
    Xử lý các thao tác liên quan đến database như tạo connection mới, đóng connection, chèn vào database, cập nhật database…

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    <?php
    class database{
     
     private $connection = null;
     
     function __construct(){
      $this->connection("localhost", "root", "", "test");
     }
     
     /** 
      * Tạo connection mới
      *  */
     public function connection( $host, $user, $password, $database )
     {
      $this->connection = new mysqli( $host, $user, $password, $database );
      if( mysqli_connect_errno() )
      {
       trigger_error('Error connecting to host. '.$this->connection->error, E_USER_ERROR);
      }
     }
     
     /**
      * Đóng connection
      * @return void
      */
     public function closeConnection()
     {
      $this->connection->close();
     }
     
     /** Chèn vào database */
     public function insert($table, $data)
     {
      // Khởi tạo giá trị cho biến fields và values
      $fields  = "";
      $values = "";
      
      // populate them
      foreach ($data as $f => $v)
      {
       $fields  .= "`$f`,";
       $values .= ( is_numeric( $v ) && ( intval( $v ) == $v ) ) ? $v."," : "'$v',";
      }
      
      // xóa dấu phẩy cuối cùng ,
      $fields = substr($fields, 0, -1);
      // xóa dấu phẩy cuối cùng ,
      $values = substr($values, 0, -1);
      
      $insert = "INSERT INTO $table ({$fields}) VALUES({$values})";
      $this->executeQuery( $insert );
      return true;
     }
     
     /** Update dữ liệu vào database */
     public function update( $table, $data, $condition )
     {
      $update = "UPDATE " . $table . " SET ";
      foreach( $data as $field => $value )
      {
       $update .= "`" . $field . "`='{$value}',";
      }
       
      // Xóa dấu phẩy sau cùng ,
      $update = substr($update, 0, -1);
      if( $condition != '' )
      {
       $update .= "WHERE " . $condition;
      }
    //   echo $update . "<br/>";
      $this->executeQuery( $update );
       
      return true;
       
     }
     
     /** Chạy câu lệnh query */
     public function executeQuery($queryStr)
     {
      // Cho phép chèn chữ tiếng việt vào database
      $this->connection->set_charset("utf8");
      if( !$result = $this->connection->query($queryStr) )
      {
       trigger_error('Error executing query: '.$this->connection->error, E_USER_ERROR);
       exit();
      }
     }
     
     public function numRows($queryStr)
     {
    //   echo $queryStr."<br/>";
      return $this->connection->query($queryStr)->num_rows;
     }
     
     public function getAll($queryStr){
      $arrayResult = array();
    //   echo $queryStr; 
      $this->connection->set_charset("utf8");
      $query = $this->connection->query($queryStr);
      while ($row = $query->fetch_array(MYSQLI_ASSOC)) {
       $arrayResult[] = $row;
      }
      return $arrayResult;
     }
    }

    Lưu ý là trong file database.php này, mình đã quy định sẵn câu query connection nên nếu bạn muốn dùng thì phải chỉnh sửa giá trị này.

  4. Trang login.php:
    Với html và ajax để đăng nhập.
    Trang checkLogin.php để kiểm tra thông tin đăng nhập

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <?php
    session_start();
    include "database.php";
    
    $db = new database();
    $username = $_REQUEST['username'];
    $password = $_REQUEST['password'];
    
    if($result = $db->numRows("select * from login where `username` = '".$username."' and `password` = '".$password."'") > 0)
    {
     $_SESSION['logged'] = $username;
     echo "ok";
     exit();
    }
    else{
     $errors = "Thông tin tài khoản sai";
     echo $errors;
    }

    Nếu bạn nào chưa rõ thì có thể vào bài post mình đã up về login form trong php trước đây. Chỉ khác là lần này mình đã dùng lớp database để lấy username và password từ database lên.

  5. Trang index.php:
    Trang index.php có tác dụng: Có form gửi tin nhắn cho user khác:

    Nếu chưa login vào thì quay ngược trở lại trang login.php:

    1
    2
    3
    4
    5
    6
    7
    8
    <?php session_start();?>
    <?php 
     if(!$_SESSION['logged'])
     {
      header("Location: login.php");
      die();
     }
    ?>

    Trang index.php phải thêm vào các thư viện jQuery và colorbox để hiển thị popup và truyền dữ liệu thông qua AJAX.
    Form gửi tin nhắn và pluggin jQuery là colorbox để show các tin nhắn tới tài khoản user hiện tại.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    <html>
    <head>
     <title>www.phamngoctan.com Hiệu ứng tự động gửi notification khi có tin nhắn mới</title>
     <script type="text/javascript" src="lib/js/jquery-1.9.1.js"></script>
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
     <script src="lib/js/jquery.colorbox.js"></script>
     <link rel="stylesheet" type="text/css" href="lib/css/style.css"> 
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    </head>
    
    <body>
    
     <div id="header">
         <ul id="topnav">
            <li><a href="javascript:void(0)">Trang chủ</a></li>
            <li><a href="javascript:void(0)">Danh mục</a></li>
            <li><a href="javascript:void(0)">Liên hệ</a></li>
            <li><a href="javascript:void(0)">Quảng cáo</a></li>
            <li><a href="javascript:void(0)" id="logout">Logout</a></li>
         </ul>
         <a class="inline" href="#inline_content">
          <div id="notification">
              <div id="notice"></div>
       </div>
         </a>
     </div>
     <!-- Phần này được giấu đi để show thông tin của tin nhắn -->
     <div style='display:none'>
         <div id='inline_content'>
         <div id="close">X</div>
         <div id="content_notification"></div>
         </div>
     </div>
     
     <h3>Gửi tin nhắn</h3>
     <table>
      <tr>
       <td><label for="message">Lời nhắn</label></td>
       <td><textarea id="message" rows="5" cols="80" placeholder="Nội dung tin nhắn"></textarea></td>
      </tr>
      <tr>
       <td><label for="receiver_username">Người nhận</label></td>
       <td><input id="receiver_username" name="receiver_username" type="text" placeholder="Username người nhận"/></td>
      </tr>
      <tr>
       <td><label for="btn_send">Cuối cùng:</label></td>
       <td><input type="button" id="btn_send" name="btn_send" value="Gửi tin"/></td>
      </tr>
      <tr><td colspan="2"><div id="response" style="color:green;"></div></td></tr>
     </table>
    </body>
    </html>

    Nguyên tắc của việc gửi tin nhắn là lấy nội dung từ textarea và username người nhận để lưu vào database. Bên cạnh đó thì server cũng phải kiểm tra xem người nhận có tồn tại hay không, ngoài ra ta cũng nên dùng javascript để bắt các lỗi như chưa nhập nội dung tin nhắn, chưa nhập username người nhận… Souce code:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    // Gửi tin nhắn cho user khác
      jQuery("#btn_send").click(function(){
       var response = document.getElementById("response");
       response.innerHTML = "";
       var message = document.getElementById("message").value;
       var receiver_username = document.getElementById("receiver_username").value;
    
       if(message.length < 25)
       {
        if(message.length == 0)
         response.innerHTML = "Mời bạn nhập nội dung tin nhắn";
        else
         response.innerHTML = "Tin nhắn quá ngắn, ít nhất 25 từ mới được gửi";
       }
       else if(receiver_username.length < 5)
       {
        if(receiver_username.length == 0)
         response.innerHTML = "Bạn chưa nhập username của người nhận";
        else
         response.innerHTML = "Username quá ngắn, ít nhất 5 ký tự";
       }
       else
       {
        $.ajax({
         type: "POST", 
         url         : href + "sendMessage.php?message=" + message + "&receiver_username=" + receiver_username,
         data        : null,
         success: function(data)
         {
          if(data.trim() == "4")
           response.innerHTML = "Bạn không thể tự gửi tin nhắn cho bản thân mình được";
          else if(data.trim() == "3")
           response.innerHTML = "Người nhận tin nhắn không tồn tại";
          else if(data.trim() == "2")
           response.innerHTML = "Username bạn điền không tồn tại";
          else if(data.trim() == "1")
          {
           response.innerHTML = "Gửi tin nhắn thành công";
           document.getElementById("message").value = "";
           document.getElementById("receiver_username").value = "";
          }
          else
           response.innerHTML = "Có lỗi khi gửi tin nhắn";
         }
        });
       }
      });

    Theo dòng lưu chuyển của dữ liệu thì ta sẽ đến file sendMessage.php. Các dữ liệu được truyền qua sẽ được kiểm tra lại lần nữa trước khi chèn tin nhắn vào database:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    <?php
    session_start();
    include "database.php";
    
    $db = new database();
    $message = $_REQUEST['message'];
    $receiver_username = $_REQUEST['receiver_username'];
    $sender_username = $_SESSION['logged'];
    // Đặt time zone là của thành phố hồ chí minh để lấy thời gian gửi
    date_default_timezone_set('Asia/Ho_Chi_Minh');
    $time_now = date('d-m-Y H:i:s');
    // Kiểm tra người gửi có phải là người nhận không
    if($receiver_username == $sender_username)
    {
     echo "4";
    }
    // Kiểm tra người nhận có tồn tại hay không
    else if($db->numRows("select * from login where `username` = '" . $receiver_username . "'") <= 0)
    {
     echo "3";
    }
    else if($db->numRows("select * from login where `username` = '".$sender_username."'") <= 0)
    {
     echo "2";
    }
    else
    {
     $data = array('sender_username' => $sender_username,
       'receiver_username' => $receiver_username,
       'message' => $message,
       'timeSending' => $time_now);
     if($db->insert('notification', $data))
      echo "1";
     else
      echo "0";
    }

    Một số thông báo lỗi khi gửi tin nhắn:

    Dùng jQuery để bắt sự kiện click vào biểu tượng bên góc phải trên cùng, hiển thị một popup mới hiển với tất cả tin nhắn của người dùng hiện tại

    Đoạn code jQuery bắt sự kiện click, lấy tất cả tin nhắn về và hiển thị lên trang popup colorbox:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    var href = "http://localhost/phptut/notification/";
      // Lấy tất cả tin nhắn rồi show ra trên div content_notification
      jQuery("#notification").click(function(){
       $.ajax({
        type: "POST", 
        url         : href + "getAllNoti.php",
        data        : null,
        success: function(data)
        {
         $('#content_notification').html(data);
        }
       });
       $(".inline").colorbox({
        inline:true, 
        width:"70%",
        top: "80px"
       });
       
      });
      // Đóng cái popup lại
      jQuery("#close").click(function(){
       jQuery(this).colorbox.close();
      });

    Lúc này, hệ thống sẽ vào file getAllNoti.php để lấy ra các tin nhắn của user hiện tại rồi trả dữ liệu về trên trang popup thông qua AJAX mà không phải refresh lại trang. File getAllNoti.php:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <?php
    session_start();
    include "database.php";
    $db = new database();
    $username = $_SESSION['logged'];
    $messages = $db->getAll("select a.id, a.message, a.timeSending, b.name from `notification` as a, `login` as b where a.receiver_username = '" . $username ."' and a.sender_username = b.username ");
    // var_dump($messages);
    echo "<table>";
    foreach($messages as $message)
    {
     echo "<tr><td>".$message["timeSending"].": Bạn ".$message["name"] . " gửi tin nhắn: </td><td>" . $message["message"] . "<td/><tr/>";
     if($message["is_read"] == 0)
     {
      $data = array("is_read" => "1");
      $db->update("notification", $data, "id = ".$message["id"]);
     }
    }
    echo "</table>";

    Source code tự động lấy tin nhắn về từ server thông qua hàm setInterval của javascript và lấy số lượng tin nhắn chưa đọc qua AJAX, nếu có tin nhắn chưa đọc thì sẽ hiển thị số lượng tin nhắn chưa đọc trên nền đỏ giống facebook, nếu không thì vẫn để biểu tượng cũ:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // Tự động lấy các notification về
      setInterval(function() {
       //call $.ajax here
       $.ajax({
        type: "POST", 
        url         : href + "checkNoti.php",
        data        : null,
        success: function(data)
        {
         //console.log(data.trim() + "f");
         if(data.trim() > 0)
         {
          //console.log(data);
          $('#notification').css('background-image', "url("+ href +"/lib/images/noti-red.png)");
          $('#notice').html(data.trim());
         }
         else
         {
          $('#notification').css('background-image', "url("+ href +"/lib/images/noti.png)");
          $('#notice').html("");
         }
        }
       });
      }, 1000);

    File checkNoti.php với chức năng lấy số lượng tin nhắn chưa đọc:

    1
    2
    3
    4
    5
    6
    7
    <?php
    session_start();
    include "database.php";
    
    $db = new database();
    $receiver_id = $_SESSION['logged'];
    echo $db->numRows("select * from notification where is_read = 0 and `receiver_username` = '" . $receiver_id . "'");

    Thêm một công đoạn nữa đó chính là Logout:

    1
    2
    3
    4
    // Nút loggout
      jQuery("#logout").click(function(){
       window.location.href = href + "logOut.php";
      });

    File logOut.php với nhiệm vụ là hủy session đã login và đẩy về trang login.php ban đầu:

    1
    2
    3
    4
    <?php
    session_start();
    $_SESSION['logged'] = false;
    header("location: login.php");

    File index.php hoàn chỉnh:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    <?php session_start();?>
    <?php 
     if(!$_SESSION['logged'])
     {
      header("Location: login.php");
      die();
     }
    ?>
    <html>
    <head>
     <title>www.phamngoctan.com Hiệu ứng tự động gửi notification khi có tin nhắn mới</title>
     <script type="text/javascript" src="lib/js/jquery-1.9.1.js"></script>
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
     <script src="lib/js/jquery.colorbox.js"></script>
     <link rel="stylesheet" type="text/css" href="lib/css/style.css"> 
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    </head>
    <body>
     <div id="header">
         <ul id="topnav">
            <li><a href="javascript:void(0)">Trang chủ</a></li>
            <li><a href="javascript:void(0)">Danh mục</a></li>
            <li><a href="javascript:void(0)">Liên hệ</a></li>
            <li><a href="javascript:void(0)">Quảng cáo</a></li>
            <li><a href="javascript:void(0)" id="logout">Logout</a></li>
         </ul>
         <a class="inline" href="#inline_content">
          <div id="notification">
              <div id="notice"></div>
       </div>
         </a>
     </div>
     <!-- Phần này được giấu đi để show thông tin của tin nhắn -->
     <div style='display:none'>
         <div id='inline_content'>
         <div id="close">X</div>
         <div id="content_notification"></div>
         </div>
     </div>
     <h3>Gửi tin nhắn</h3>
     <table>
      <tr>
       <td><label for="message">Lời nhắn</label></td>
       <td><textarea id="message" rows="5" cols="80" placeholder="Nội dung tin nhắn"></textarea></td>
      </tr>
      <tr>
       <td><label for="receiver_username">Người nhận</label></td>
       <td><input id="receiver_username" name="receiver_username" type="text" placeholder="Username người nhận"/></td>
      </tr>
      <tr>
       <td><label for="btn_send">Cuối cùng:</label></td>
       <td><input type="button" id="btn_send" name="btn_send" value="Gửi tin"/></td>
      </tr>
      <tr><td colspan="2"><div id="response" style="color:green;"></div></td></tr>
     </table>
    </body>
    </html>
    <script type="text/javascript">
     jQuery(document).ready(function(){
      var href = "http://localhost/phptut/notification/";
      // Lấy tất cả tin nhắn rồi show ra trên div content_notification
      jQuery("#notification").click(function(){
       $.ajax({
        type: "POST", 
        url         : href + "getAllNoti.php",
        data        : null,
        success: function(data)
        {
         $('#content_notification').html(data);
        }
       });
       $(".inline").colorbox({
        inline:true, 
        width:"70%",
        top: "80px"
       });
       
      });
    
      // Đóng cái popup lại
      jQuery("#close").click(function(){
       jQuery(this).colorbox.close();
      });
      
      // Chạy lần đầu tiên để lấy message về
      $.ajax({
       type: "POST", 
       url         : href + "checkNoti.php",
       data        : null,
       success: function(data)
       {
        //console.log(data.trim());
        if(data.trim() > 0)
        {
         //console.log(data);
         $('#notification').css('background-image', "url("+ href +"/lib/images/noti-red.png)");
         $('#notice').html(data.trim());
        }
        else 
        {
         $('#notification').css('background-image', "url(" + href + "/lib/images/noti.png)");
         $('#notice').html("");
        }
       }
      });
      
      // Tự động lấy các notification về
      setInterval(function() {
       //call $.ajax here
       $.ajax({
        type: "POST", 
        url         : href + "checkNoti.php",
        data        : null,
        success: function(data)
        {
         //console.log(data.trim() + "f");
         if(data.trim() > 0)
         {
          //console.log(data);
          $('#notification').css('background-image', "url("+ href +"/lib/images/noti-red.png)");
          $('#notice').html(data.trim());
         }
         else
         {
          $('#notification').css('background-image', "url("+ href +"/lib/images/noti.png)");
          $('#notice').html("");
         }
        }
       });
      }, 1000);
      // Nút loggout
      jQuery("#logout").click(function(){
       window.location.href = href + "logOut.php";
      });
      // Gửi tin nhắn cho user khác
      jQuery("#btn_send").click(function(){
       var response = document.getElementById("response");
       response.innerHTML = "";
       var message = document.getElementById("message").value;
       var receiver_username = document.getElementById("receiver_username").value;
    
       if(message.length < 25)
       {
        if(message.length == 0)
         response.innerHTML = "Mời bạn nhập nội dung tin nhắn";
        else
         response.innerHTML = "Tin nhắn quá ngắn, ít nhất 25 từ mới được gửi";
       }
       else if(receiver_username.length < 5)
       {
        if(receiver_username.length == 0)
         response.innerHTML = "Bạn chưa nhập username của người nhận";
        else
         response.innerHTML = "Username quá ngắn, ít nhất 5 ký tự";
       }
       else
       {
        $.ajax({
         type: "POST", 
         url         : href + "sendMessage.php?message=" + message + "&receiver_username=" + receiver_username,
         data        : null,
         success: function(data)
         {
          if(data.trim() == "4")
           response.innerHTML = "Bạn không thể tự gửi tin nhắn cho bản thân mình được";
          else if(data.trim() == "3")
           response.innerHTML = "Người nhận tin nhắn không tồn tại";
          else if(data.trim() == "2")
           response.innerHTML = "Username bạn điền không tồn tại";
          else if(data.trim() == "1")
          {
           response.innerHTML = "Gửi tin nhắn thành công";
           document.getElementById("message").value = "";
           document.getElementById("receiver_username").value = "";
          }
          else
           response.innerHTML = "Có lỗi khi gửi tin nhắn";
         }
        });
       }
      });
     });
    </script>

    Lưu ý là mình đã đặt cái href là đường dẫn tĩnh, các bạn lấy source code về phải thay đổi giá trị đường dẫn mình quy định mới sử dụng được.

  6. Các tính năng của bài post này:
    Khi user1 gửi tin nhắn cho user2 thì ngay lập tức user2 sẽ nhận được tin nhắn, đồng thời biểu tượng bên góc phải màn hình sẽ hiển thị số lượng tin nhắn chưa đọc. Hỗ trợ đăng nhập và đăng xuất. Cho phép người dùng gửi tin nhắn tới người dùng khác.
Kết luận:
  • Tutorial này tuy dài nhưng mà về bản chất thì khá là ngắn. Chỉ cần bạn hiểu trọng tâm của bài này là hàm setInterval để tự động lấy dữ liệu về sau một khoảng thời gian quy định là mọi chuyện đã xong. Còn lại thì tùy vào khả năng của mỗi người mà hoàn thành nhanh hay chậm hơn chút.
  • Nếu có ý kiến gì về tutorial hoặc đóng góp cho tối ưu hơn thì các bạn hãy để lại comment ở phía dưới nha. Mình sẽ rất cảm kích về điều đó.
Chúc các bạn thành công!
Phạm Ngọc Tân

Related Posts

Comments (2)

  1. Hiếu Lương Công
    January 19, 2014

    Nhận xét này đã bị tác giả xóa.

    Reply
  2. Nguyễn Mai
    March 02, 2014

    (h) Hay quá cám ơn thầy về bài viết.

    Reply

Leave a Comment!

Your email address will not be published. Required fields are marked *