I built a CodeIgniter version of the
server-sent-events sample. It's modified from the Github example a tiny bit but works as expected.
Controller: Eventsource.php
PHP Code:
<?php
class Eventsource extends CI_Controller
{
function __construct()
{
parent::__construct();
$this->load->helper('url');
$this->load->model('eventsource_m');
}
public function index()
{
$this->load->view('eventsource_v');
}
public function sse()
{
$this->eventsource_m->process();
}
}
View: eventsource_v.php
PHP Code:
<html>
<head>
<meta charset="UTF-8">
<title>Server-sent events demo</title>
</head>
<body>
<button>Close the connection</button>
<ul>
</ul>
<script>
var button = document.querySelector('button');
var evtSource = new EventSource(<?= "'".base_url('eventsource/sse', 'https')."'"; ?> );
console.log(evtSource.withCredentials);
console.log(evtSource.readyState);
console.log(evtSource.url);
var eventList = document.querySelector('ul');
evtSource.onopen = function () {
console.log("Connection to server opened.");
};
evtSource.onmessage = function (e) {
var newElement = document.createElement("li");
newElement.textContent = "message: " + e.data;
eventList.appendChild(newElement);
};
evtSource.onerror = function () {
console.log("EventSource failed.");
};
button.onclick = function () {
console.log('Connection closed');
evtSource.close();
};
</script>
</body>
</html>
Model: Eventsource_m.php
PHP Code:
<?php
class Eventsource_m extends CI_Model
{
public function process()
{
date_default_timezone_set("America/New_York");
header("Content-Type: text/event-stream");
// 1 is always true, so repeat the while loop forever (aka event-loop)
while (1)
{
$curDate = date(DATE_ISO8601);
// Send a simple message at 2 second intervals.
echo 'data: This is a message at time ' . $curDate, "\n\n";
// flush the output buffer and send echoed messages to the browser
while (ob_get_level() > 0)
{
ob_end_flush();
}
flush();
// break the loop if the client aborted the connection (closed the page)
if (connection_aborted())
{
break;
}
// sleep for 2 seconds before running the loop again
sleep(2);
}
}
}
Direct the browser to
https://your_domain/eventsource and see a new message every two seconds. Clearly the EventSource messages can be sent from a model.
The only tricky bit was in the JavaScript with setting the URL for EventSource.
PHP Code:
var evtSource = new EventSource(<?= "'".base_url('eventsource/sse', 'https')."'"; ?> );
Notice how I had to explicitly concatenate single quotes around the output of
base_url(). Without those JavaScript could not properly evaluate the argument. This is a common issue when combining PHP and JavaScript.
Using the browsers JavaScript console is important when trying to figure out what, if any, failures are occurring. I spotted the above issue right away.
Hopefully, all this helps.
It's not clear to me what you want to happen when processing is complete.
Based on your view it looks like you want to send data back to drive a progress-bar. If so, a message value equal to "100" would make for a good signal to disconnect the EventSource and move on to whatever is supposed to happen.