-2

I'm building a two-way chat application that stores messages into a MySQL database. I would like to use Server Sent Events and have the PHP and HTML all in one page but the problem I'm facing is that the header cannot be set to text/event-stream or I will break the HTML.

My question is how can I have the PHP, JS and HTML on the same page when using Server Sent Events?

Here is my opening JS. I set the EventSource to index.php even though this might be wrong.

<html>
        <head>
        <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0" />
        <link rel="stylesheet" type="text/css" href="style.css">
        </head>
        <script>
        if(typeof(EventSource) !== "undefined") {
          var source = new EventSource("index.php");
          source.onmessage = function(event) {
           document.getElementsByClassName("message").innerHTML = event.data;
         };
        }else {
         document.getElementsByClassName("message").innerHTML = "Sorry, your browser does not support server-sent events...";
        }
        </script>
        <h1>LoRa Chat</h1>
        <?php
           $SSE = (@$_SERVER["HTTP_ACCEPT"] == "text/event-stream");
           if($SSE){
            header('Cache-Control: no-cache');
            header("Content-Type: text/event-stream");
           }
           else {
            header("Content-Type: text/html");
           }

            //Database Stuff
            $connect = mysqli_connect('localhost', 'user', 'Pass');
            mysqli_select_db($connect,"allmessages");
            $sql = "SELECT *, if(mymessages > yourmessages, mymessages, yourmessages) FROM lora_messages";
            $results = mysqli_query($connect, $sql);
            while($row = mysqli_fetch_array($results)) {
                if ($row ['mymessages'] > $row ['yourmessages']){
        ?>
        <div class='chat'>
        <div class='mine messages'>
        <div class='message'>
        <?php echo "data: ".$row['mymessages']; flush();?>
        </div>
        </div>
        <?php
            }
               elseif ($row ['mymessages'] < $row ['yourmessages']){
        ?>
        <div class='chat'>
        <div class='yours messages'>
        <div class='message'>
        <?php echo "data: ".$row['yourmessages']; flush();?>
        </div>
        </div>
        <?php
            }
        }
        ?>
        <div class="fixed">
        <form action="<?php echo $_SERVER['PHP_SELF']; ?>" Method="POST">
        <input type="text" id="body" name="mymessage">
        <input type="submit" value="Submit" name="submit">
        </form>
        </div>
<br>
</body>
</html>

EDIT: I have tried separating the PHP the HTML and put the PHP logical part outside the HTML. I'm able to get Server Sent Events via inspector in Chrome but not sure how to loop through the DB entries in JS. I'm not comfortable with JS syntax.

<?php
$SSE = (@$_SERVER["HTTP_ACCEPT"] == "text/event-stream");
if($SSE){
   header("Content-Type: text/event-stream");
   header('Cache-Control: no-cache');
   if(isset($_POST['submit'])){
      $send = $_POST['mymessage'];
      $sendmsg = "INSERT INTO lora_messages (mymessages, yourmessages) VALUES ('".$send."', '')";
   }
   if (!empty($_GET['yourmessage'])){
       $recieve = $_GET['yourmessage'];
       $recievemsg = "INSERT INTO lora_messages (mymessages, yourmessages) VALUES ('', '".$recieve."')";
   }

   $connect = mysqli_connect('localhost', 'root', 'Walcott34');
   mysqli_select_db($connect,"allmessages");
   $sql = "SELECT *, if(mymessages > yourmessages, mymessages, yourmessages) FROM lora_messages";
   $sqlrecieve = mysqli_query($connect, $recievemsg);
   $sqlsend = mysqli_query($connect, $sendmsg);
   $results = mysqli_query($connect, $sql);
   while($row = mysqli_fetch_array($results)) {
       if ($row ['mymessages'] > $row ['yourmessages']){
          echo "data: ".$row['mymessages']."\n\n";
       }
       elseif ($row ['mymessages'] < $row ['yourmessages']){
          echo "data: ".$row['yourmessages']."\n\n";
       }
   ob_flush();
   flush();
  }
}

else {

?>

<html>
        <head>
        <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0" />
        <link rel="stylesheet" type="text/css" href="style.css">
        </head>
        <script>
        if(typeof(EventSource) !== "undefined") {
          var source = new EventSource("index2.php");
          source.onmessage = function(e){
              document.getElementById("mymessages").innerHTML = event.data;
              document.getElementById("yourmessages").innerHTML = event.data;

         };
        }else {
         document.getElementsById('message').innerHTML = "Sorry, your browser does not support server-sent events...";
        }
        </script>
        <h1>LoRa Chat</h1>
        <div class='chat'>
        <div class='mine messages'>
        <div class='message'>
        <div id='mymessage'>
        </div>
        </div>
        </div>
        <div class='chat'>
        <div class='yours messages'>
        <div class='message'>
        <div id='yourmessage'>
        </div>
        </div>
        </div>
        <div class="fixed">
        <form action="<?php echo $_SERVER['PHP_SELF']; ?>" Method="POST">
        <input type="text" id="body" name="mymessage">
        <input type="submit" value="Submit" name="submit">
        </form>
        </div>
<br>
</body>
</html>

<?php } ?>



fixnode
  • 97
  • 3
  • 8
  • 32
  • 1
    What do you mean by it breaks your HTML? – wuno Mar 31 '20 at 04:57
  • @wuno I only get text (no html) on my site if I use header('Content-Type: text/event-stream') also SSE doesn't seem to work when the PHP is on the same site. Doing things like var source = new EventSource(); does not work either. – fixnode Mar 31 '20 at 05:06
  • 1
    Please read: [Should we ever check for mysqli_connect() errors manually?](https://stackoverflow.com/q/58808332/1839439) – Dharman Mar 31 '20 at 10:27
  • send back json from event stream, your mixing in html with `echo "data:` etc it doesn't work like that, eww php https://github.com/lcherone/sse-chat-example ;p – Lawrence Cherone Apr 01 '20 at 16:43
  • @LawrenceCherone I'm not quite following. I've tried to do in the EventSource and but that does not work. My intention here is to have the SSE server (php) and HTML/JS all in one file/program. I have yet to see this done. Every example I see separates the PHP SSE part from the HTML part – fixnode Apr 01 '20 at 17:46
  • What have you tried to debug the problem? Can you share more details such that others can reproduce the problem? – Nico Haase Apr 02 '20 at 15:03
  • @NicoHaase please see my recent EDIT. – fixnode Apr 02 '20 at 15:27
  • That INSERT query is widely open for SQL injection. Please don't use it in production, ever. – Nico Haase Apr 02 '20 at 15:38
  • @NicoHaase this application will live on an offline hotspot (raspberry pi zero). The only one connecting to it will be myself. – fixnode Apr 02 '20 at 15:51

1 Answers1

0

If your after it being in one file you just need the one outer if statement which separates the two logical parts.

<?php
if ($_SERVER["HTTP_ACCEPT"] === 'text/event-stream') {
 // event stream code

  ...

  while (true) {

  ...

} else {
// client side code
?>
 <head>
        <meta name="viewport" content="w
 ...

<?php }

You cant intertwine the two parts like your doing:

<div class='message'>
 <?php echo "data: $row['mymessages']"; flush();?>
</div>

Your serverside part is incomplete but that's beyond the scope of the question,ive commented with a link to a working example.

Lawrence Cherone
  • 46,049
  • 7
  • 62
  • 106
  • I'm not quite following. How can I not intertwine the two parts? I need to loop through all of the variables from MySQL. – fixnode Apr 02 '20 at 02:09
  • your not meant to output first, that's what `$_SERVER["HTTP_LAST_EVENT_ID"]` is for so you can pick up on or show initial data, though you could do it first but not mix it in it dont work like that. – Lawrence Cherone Apr 02 '20 at 12:26